bzoj 4034: [HAOI2015]T2

来源:互联网 发布:网络加速器翻墙 编辑:程序博客网 时间:2024/04/29 00:16

Description

 有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个

操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。

Input

 第一行包含两个整数 N, M 。表示点数和操作数。

接下来一行 N 个整数,表示树中节点的初始权值。
接下来 N-1 行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) 。
再接下来 M 行,每行分别表示一次操作。其中第一个数表示该操
作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。

Output

 对于每个询问操作,输出该询问的答案。答案之间用换行隔开。

Sample Input

5 5
1 2 3 4 5
1 2
1 4
2 3
2 5
3 3
1 2 1
3 5
2 1 2
3 3

Sample Output

6
9
13

HINT

 对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不


会超过 10^6 。

Source

鸣谢bhiaibogf提供


一开始想用树链剖分,结果发现只需要维护dfs序就可以了

我用的是线段树维护。。没去想怎么用树状数组维护

首先dfs记录进入的时刻和弹出的时刻。进入权值为正,弹出为负

然后要查询路径的话直接查询1到x的权值和就可以了

单点修改就直接线段树上修改

子树就该即修改进入和弹出中间的那一段

每段维护正权值点和以及负权值点和。最后减一下就可以了

*记得开long long

#include<cstdio>using namespace std;struct line{     int s,t;     int next;}a[200001];int head[100001];int edge;inline void add(int s,int t){ a[edge].next=head[s];     head[s]=edge;     a[edge].s=s;     a[edge].t=t;}int w[200001],b[200001];int ld[200001],rd[200001];bool v[200001];int tot;struct tree{     int l,r;     long long s1,s2;     long long x1,x2;     long long tag;}tr[800001];inline void up(int p){     tr[p].s1=tr[p*2].s1+tr[p*2+1].s1;     tr[p].x1=tr[p*2].x1+tr[p*2+1].x1;     tr[p].s2=tr[p*2].s2+tr[p*2+1].s2;     tr[p].x2=tr[p*2].x2+tr[p*2+1].x2;}inline void down(int p){     long long ll1,ll2,lr1,lr2;     long long x=tr[p].tag;     ll1=tr[p*2].x1;     ll2=tr[p*2].x2;     lr1=tr[p*2+1].x1;     lr2=tr[p*2+1].x2;     tr[p*2].s1+=ll1*x;     tr[p*2].s2+=ll2*x;     tr[p*2+1].s1+=lr1*x;     tr[p*2+1].s2+=lr2*x;     tr[p*2].tag+=x;     tr[p*2+1].tag+=x;     tr[p].tag=0;}inline void build(int p,int l,int r){     tr[p].l=l;     tr[p].r=r;     if(l!=r)     {          int mid=(l+r)/2;          build(p*2,l,mid);          build(p*2+1,mid+1,r);          up(p);     }     else     {       if(w[l]>0)       {               tr[p].s1=b[w[l]];               tr[p].x1=1;          }          else          {               tr[p].s2=b[-w[l]];               tr[p].x2=1;          }     }}inline void add1(int p,int l,int r,long long x){     if(l<=tr[p].l&&tr[p].r<=r)     {          if(tr[p].x1==1)               tr[p].s1+=x;          else               tr[p].s2+=x;     }     else     {       down(p);          int mid=(tr[p].l+tr[p].r)/2;          if(l<=mid)               add1(p*2,l,r,x);          if(r>mid)               add1(p*2+1,l,r,x);          up(p);     }}inline void add2(int p,int l,int r,long long x){     if(l<=tr[p].l&&tr[p].r<=r)     {          long long l1=tr[p].x1,l2=tr[p].x2;          tr[p].s1+=x*l1;          tr[p].s2+=x*l2;          tr[p].tag+=x;     }     else     {       down(p);          int mid=(tr[p].l+tr[p].r)/2;          if(l<=mid)               add2(p*2,l,r,x);          if(r>mid)               add2(p*2+1,l,r,x);           up(p);     }}tree nw;inline tree ask(int p,int l,int r){     if(l<=tr[p].l&&tr[p].r<=r)          return tr[p];     else     {       down(p);          int mid=(tr[p].l+tr[p].r)/2;          tree ans1=nw,ans2=nw,ans=nw;          bool flag1=false,flag2=false;          if(l<=mid)          {               flag1=true;               ans1=ask(p*2,l,r);          }          if(r>mid)          {               flag2=true;               ans2=ask(p*2+1,l,r);          }          if(flag1)          {               if(flag2)               {                    ans.s1=ans1.s1+ans2.s1;                    ans.s2=ans1.s2+ans2.s2;                    ans.x1=ans1.x1+ans2.x1;                    ans.x2=ans1.x2+ans2.x2;               }               else                    ans=ans1;          }          else               ans=ans2;          return ans;     }}inline void dfs(int d){ tot++; ld[d]=tot; w[tot]=d; v[d]=true;     int i;     for(i=head[d];i!=0;i=a[i].next)     {          int t=a[i].t;          if(!v[t])               dfs(t);     }     tot++;     rd[d]=tot; w[tot]=-d;}int main(){     int n,m;     scanf("%d%d",&n,&m);     int i;     for(i=1;i<=n;i++)          scanf("%d",&b[i]);     int s,t;     for(i=1;i<=n-1;i++)     {          scanf("%d%d",&s,&t);          edge++;          add(s,t);          edge++;          add(t,s);     }     dfs(1);     build(1,1,tot);     int x;     for(i=1;i<=m;i++)     {          scanf("%d",&x);          if(x==1)          {               scanf("%d%d",&s,&t);               add1(1,ld[s],ld[s],t);               add1(1,rd[s],rd[s],t);          }          else if(x==2)          {               scanf("%d%d",&s,&t);               add2(1,ld[s],rd[s],t);          }          else          {               scanf("%d",&s);               tree xt=ask(1,1,ld[s]);               printf("%lld\n",xt.s1-xt.s2);          }     }     return 0;}


0 0
原创粉丝点击