[BZOJ4034] [HAOI2015]T2

传送门

http://www.lydsy.com/JudgeOnline/problem.php?id=4034

题目大意

对于一棵树支持
1:单点修改
2:子树修改
3:单点到根的路径查询

题解

ydc大爷的题解http://ydc.blog.uoj.ac/blog/336
dfs序+线段树
对于操作1,相当于对子树都加上同一个值
对于操作2,相当于对于v的子树都加上 (depudepv+1)x ,我们把它再拆一下就是 depux+(1depv)x ,就分离成立与每个点u的深度有关的部分和无关的部分,分开维护即可
10^6如果是个链显然爆longint,所以……

const
 maxn=100005;
var
 dep,t:array[0..maxn]of int64;
 x:array[0..maxn]of int64;
 z:array[0..4*maxn,1..2]of longint;
 y:array[0..maxn,1..2]of int64;
 w:array[0..6*maxn,1..6]of int64;
 i,j,k:longint;
 n,m,len:longint;
 a,b,c:int64;
 head,tail,v,tt:longint;
procedure init(a,b:longint);
begin
 z[len,1]:=b;
 if z[a,2]=0
 then z[a,2]:=len else z[z[a,1],2]:=len;
 z[a,1]:=len; inc(len);
end;

procedure deep;
begin
 t[1]:=1; head:=1; tail:=2;
 while head<tail do
  begin
   v:=t[head]; tt:=z[v,2]; inc(head);
   while tt<>0 do
    begin
     if dep[z[tt,1]]=0 then begin
      dep[z[tt,1]]:=dep[v]+1;
      t[tail]:=z[tt,1]; inc(tail);
     end;
     tt:=z[tt,2];
    end;
  end;
end;

procedure dfs(a:longint);
var tt:longint;
begin
 inc(len); y[a,1]:=len; tt:=z[a,2];
 while tt<>0 do
  begin
   if y[z[tt,1],1]=0 then dfs(z[tt,1]);
   tt:=z[tt,2];
  end;
 y[a,2]:=len;
end;

procedure build(a,l,r:longint);
var mid:longint;
begin
 w[a,1]:=l; w[a,2]:=r; w[a,3]:=0; w[a,4]:=0; w[a,5]:=0; w[a,6]:=0;
 if l=r then exit;
 mid:=(l+r)>>1;
 build(a<<1,l,mid); build(a<<1+1,mid+1,r);
end;

procedure pushdown(a:longint);
begin
 if w[a,1]=w[a,2] then begin inc(w[a,3],w[a,5]); w[a,5]:=0; inc(w[a,4],w[a,6]); w[a,6]:=0; exit; end;
 inc(w[a,3],w[a,5]); inc(w[a,4],w[a,6]);
 inc(w[a<<1,5],w[a,5]); inc(w[a<<1+1,5],w[a,5]);
 inc(w[a<<1,6],w[a,6]); inc(w[a<<1+1,6],w[a,6]);
 w[a,5]:=0; w[a,6]:=0;
end;

procedure update1(a,l,r:longint;c:int64);
var mid:longint;
begin
 if (w[a,5]<>0)or(w[a,6]<>0) then pushdown(a);
 if (w[a,1]=l)and(w[a,2]=r) then begin inc(w[a,6],c); exit; end;
 mid:=(w[a,1]+w[a,2])>>1;
 if r<=mid then update1(a<<1,l,r,c) else
 if l>mid then update1(a<<1+1,l,r,c)
 else begin update1(a<<1,l,mid,c); update1(a<<1+1,mid+1,r,c); end;
end;

procedure update2(a,l,r:longint;b,c:int64);
var mid:longint;
begin
 if (w[a,5]<>0)or(w[a,6]<>0) then pushdown(a);
 if (w[a,1]=l)and(w[a,2]=r) then begin inc(w[a,5],b); inc(w[a,6],c); exit; end;
 mid:=(w[a,1]+w[a,2])>>1;
 if r<=mid then update2(a<<1,l,r,b,c) else
 if l>mid then update2(a<<1+1,l,r,b,c)
 else begin update2(a<<1,l,mid,b,c); update2(a<<1+1,mid+1,r,b,c); end;
end;

function query(a,b:longint;c:int64):int64;
var mid:longint;
begin
 if (w[a,5]<>0)or(w[a,6]<>0) then pushdown(a);
 if (w[a,1]=w[a,2])and(w[a,1]=b) then exit(w[a,3]*c+w[a,4]);
 mid:=(w[a,1]+w[a,2])>>1;
 if b<=mid
 then exit(query(a<<1,b,c))
 else exit(query(a<<1+1,b,c));
end;

begin
 readln(n,m); len:=n+1;
 for i:=1 to n do
  read(x[i]);
 for i:=1 to n-1 do
  begin
   readln(a,b);
   init(a,b); init(b,a);
  end;
 dep[1]:=1; deep;
 len:=0; dfs(1);
 build(1,1,n);
 for i:=1 to n do
  update1(1,y[i,1],y[i,2],x[i]);
 for i:=1 to m do
  begin
   read(a);
   case a of
   1:begin readln(b,c); update1(1,y[b,1],y[b,2],c); end;
   2:begin readln(b,c); update2(1,y[b,1],y[b,2],c,(1-dep[b])*c); end;
   3:begin readln(b); writeln(query(1,y[b,1],dep[b])); end;
   end;
  end;
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值