bzoj4034:[HAOI2015]树上操作

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 。

 

题解:

明明就是一道树链剖分模板题啊啊啊啊……

RE了无数次,简直是醉了,最后发现……有一个数组名是rank,大概是和库中某个函数名重了,改成rk就AC了……

好吧,言归正传

操作1对应到线段树中的单点修改

操作2因为以某节点为根的子树的编号都应该是连续的,所以可以对应到线段树中的区间修改

之前求重子时不是记过一个size吗,在这里就可以用来知道子树编号的范围

操作3比较常规,求路径上的和

还有中间求和操作要开long long,否则也会RE

 

注意:就是容器名称呵,最好有“个性”一些,千万不要和其他东西重了

 

代码:

 

  1 #include<iostream>
  2 #include<cstdio>
  3 using namespace std;
  4 
  5 const int MAXN=200005;
  6 struct node
  7 {
  8     int v;
  9     node *next;       
 10 }pool[MAXN],*h[MAXN];
 11 int cnt,tot;
 12 int fa[MAXN],dep[MAXN],size[MAXN],son[MAXN];
 13 int rk[MAXN],w[MAXN],top[MAXN],val[MAXN];
 14 
 15 void addedge(int u,int v)
 16 {
 17     node *p=&pool[++cnt],*q=&pool[++cnt];
 18     p->v=v;p->next=h[u];h[u]=p;    
 19     q->v=u;q->next=h[v];h[v]=q;
 20 }
 21 void dfs1(int u)
 22 {
 23     int v;
 24     size[u]=1;
 25     int Bson=0,sonnum=0;
 26     for(node *p=h[u];p;p=p->next)
 27         if(fa[u]!=(v=p->v))
 28         {
 29             fa[v]=u;
 30             dep[v]=dep[u]+1;
 31             dfs1(v);
 32             size[u]+=size[v];
 33             if(size[v]>Bson) Bson=size[v],sonnum=v;                   
 34         }
 35     son[u]=sonnum;
 36 }
 37 void dfs2(int u)
 38 {
 39     int v=son[u];
 40     if(v)
 41     {
 42         top[v]=top[u];
 43         rk[v]=++tot;
 44         w[rk[v]]=val[v];
 45         dfs2(v);    
 46     }
 47     for(node *p=h[u];p;p=p->next)
 48         if(fa[v=p->v]==u && v!=son[u])
 49         {
 50             top[v]=v;
 51             rk[v]=++tot;
 52             w[rk[v]]=val[v];
 53             dfs2(v);                 
 54         }
 55 }
 56 
 57 struct tree
 58 {
 59     int l,r;
 60     long long sum,lazy;
 61     tree *left,*right;       
 62 }t[4*MAXN],*root;
 63 int cnt1;
 64 void pushdown(tree *p)
 65 {
 66     if(p->lazy)
 67     {
 68         p->sum+=p->lazy*(long long)(p->r-p->l+1);
 69         if(p->left) p->left->lazy+=p->lazy;
 70         if(p->right) p->right->lazy+=p->lazy;
 71         p->lazy=0;
 72     }
 73 }
 74 void update(tree *p)
 75 {
 76     p->sum=0;
 77     if(p->left) p->sum+=p->left->sum+p->left->lazy*(long long)(p->left->r-p->left->l+1);
 78     if(p->right) p->sum+=p->right->sum+p->right->lazy*(long long)(p->right->r-p->right->l+1);     
 79 }
 80 void Build_Tree(tree *p,int l,int r)
 81 {
 82     p->l=l;p->r=r;
 83     if(l==r)
 84     {
 85         p->sum=(long long)w[l];
 86         return;
 87     }
 88     int mid=(l+r)/2;
 89     p->left=&t[++cnt1];p->right=&t[++cnt1];
 90     Build_Tree(p->left,l,mid);
 91     Build_Tree(p->right,mid+1,r);
 92     p->sum=p->left->sum+p->right->sum;
 93 }
 94 void change(tree *p,int l,int r,int c)
 95 {
 96     if(p->l==l && p->r==r)
 97     {
 98         p->lazy+=(long long)c;
 99         return;
100     }
101     pushdown(p);
102     if(p->left->r>=r) change(p->left,l,r,c);
103     else if(p->right->l<=l) change(p->right,l,r,c);
104     else change(p->left,l,p->left->r,c),change(p->right,p->right->l,r,c);
105     update(p);
106 }
107 long long query(tree *p,int l,int r)
108 {
109     if(p->l==l && p->r==r)
110         return p->sum+p->lazy*(p->r-p->l+1);
111     pushdown(p);
112     if(p->left->r>=r) return query(p->left,l,r);
113     else if(p->right->l<=l) return query(p->right,l,r);
114     else return query(p->left,l,p->left->r)+query(p->right,p->right->l,r);
115 }
116 
117 long long Sum(int x,int y)
118 {
119     long long ret=0;
120     int f1=top[x],f2=top[y];
121     while(f1!=f2)
122     {
123         if(dep[f1]<dep[f2]) swap(f1,f2),swap(x,y);
124         ret+=query(root,rk[f1],rk[x]);
125         x=fa[f1];f1=top[x];        
126     }
127     if(dep[x]>dep[y]) swap(x,y);
128     ret+=query(root,rk[x],rk[y]);
129     return ret;
130 }
131 
132 int main()
133 {
134     int n,m,i,a,b,c;
135     scanf("%d%d",&n,&m);
136     for(i=1;i<=n;i++) scanf("%d",&val[i]);
137     for(i=1;i<n;i++)
138         scanf("%d%d",&a,&b),addedge(a,b);
139     
140     dfs1(1);
141     top[1]=1;rk[1]=++tot;w[rk[1]]=val[1];
142     dfs2(1);
143     root=&t[++cnt1];Build_Tree(root,1,n);
144     
145     while(m --> 0)
146     {
147         scanf("%d",&c);
148         if(c==1)
149             scanf("%d%d",&a,&b),change(root,rk[a],rk[a],b);
150         else if(c==2)
151             scanf("%d%d",&a,&b),change(root,rk[a],rk[a]+size[a]-1,b);
152         else
153             scanf("%d",&a),printf("%lld\n",Sum(1,a));
154     }
155     
156     return 0;
157 }
View Code

 

既然选择了远方,便只顾风雨兼程
posted @ 2017-07-21 15:24  秋千旁的蜂蝶~  阅读(123)  评论(0编辑  收藏  举报