bzoj4034 (树链剖分+线段树)

Problem T2 (bzoj4034 HAOI2015)

题目大意

  给定一颗树,1为根节点,要求支持三种操作。

  操作 1 :把某个节点 x 的点权增加 a 。

  操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。  

  操作 3 :询问某个节点 x 到根的路径中所有点的点权和。

解题分析

  练手题。树链剖分+线段树。

参考程序

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cmath>
  4 #include <algorithm>
  5 using namespace std;
  6 
  7 #define V 100008
  8 #define E 200008
  9 #define lson l,m,rt << 1
 10 #define rson m+1,r,rt << 1 | 1
 11 #define LL long long
 12 
 13 struct line{
 14     int u,v,w,nt;
 15 }eg[E];
 16 int sum,lt[V];
 17 
 18 void adt(int u,int v){
 19     eg[++sum].u=u; eg[sum].v=v; eg[sum].nt=lt[u]; lt[u]=sum;
 20 }
 21 void add(int u,int v){
 22     adt(u,v); adt(v,u);
 23 }
 24 
 25 int size[V],fa[V],dep[V],son[V],w[V],top[V],rk[V];
 26 int n,m,a[V],cnt;
 27 
 28 void dfs_1(int u){
 29     size[u]=1; dep[u]=dep[fa[u]]+1; son[u]=0;
 30     for (int i=lt[u];i;i=eg[i].nt){
 31         int v=eg[i].v;
 32         if (v==fa[u]) continue;
 33         fa[v]=u;
 34         dfs_1(v);
 35         size[u]+=size[v];
 36         if (size[v]>size[son[u]]) son[u]=v;
 37     }
 38 }
 39 
 40 void dfs_2(int u,int tp){
 41     top[u]=tp; w[u]=++cnt; rk[cnt]=u;
 42     if (son[u]) dfs_2(son[u],tp);
 43     for (int i=lt[u];i;i=eg[i].nt){
 44         int v=eg[i].v;
 45         if (v==fa[u] || v==son[u]) continue;
 46         dfs_2(v,v);
 47     }
 48 }
 49 
 50 struct segment_tree{
 51     LL sum[V << 2],lazy[V << 2];
 52     void pushup(int rt){
 53         sum[rt]=sum[rt<<1]+sum[rt<<1|1];
 54     }
 55     void pushdown(int rt,int m){
 56         if (lazy[rt]){
 57             lazy[rt<<1]+=lazy[rt];
 58             lazy[rt<<1|1]+=lazy[rt];
 59             sum[rt<<1]+=lazy[rt] * (m-m/2);
 60             sum[rt<<1|1]+=lazy[rt] * (m/2);
 61             lazy[rt]=0;
 62         }
 63     }
 64     void build(int l,int r,int rt){
 65         lazy[rt]=0;
 66         if (l==r){
 67             sum[rt]=a[rk[l]];
 68             return;
 69         }
 70         int m=(l+r)/2;
 71         build(lson);
 72         build(rson);
 73         pushup(rt);
 74     }
 75     void update(int L,int R,int val,int l,int r,int rt){
 76         if (L<=l && r<=R){
 77             lazy[rt]+=val;
 78             sum[rt]+=1ll*(r-l+1)*val;
 79             return;        
 80         }
 81         pushdown(rt,r-l+1);
 82         int m=(l+r)/2;
 83         if (L <= m) update(L,R,val,lson);
 84         if (m <  R) update(L,R,val,rson);
 85         pushup(rt);
 86     }
 87     LL query(int L,int R,int l,int r,int rt){
 88         if (L<=l && r<=R){
 89             return sum[rt];
 90         }
 91         pushdown(rt,r-l+1);
 92         int m=(l+r)/2;
 93         LL res=0;
 94         if (L <= m) res+=query(L,R,lson);
 95         if (m <  R) res+=query(L,R,rson); 
 96         return res;
 97     } 
 98 }T;
 99 
100 void change(int x,int y){
101     LL res=0;
102     while (top[x]!=top[y]){
103         if (dep[top[x]]<dep[top[y]]) swap(x,y);
104         res+=T.query(w[top[x]],w[x],1,n,1);
105         x=fa[top[x]];
106     }
107     if (dep[x]>dep[y]) swap(x,y);
108     res+=T.query(w[x],w[y],1,n,1);
109     printf("%lld\n",res );
110 }
111 
112 int main(){
113     memset(lt,0,sizeof(lt)); sum=1;
114     scanf("%d %d",&n,&m);
115     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
116     for (int i=1;i<n;i++){
117         int u,v;
118         scanf("%d %d",&u,&v);
119         add(u,v);
120     }
121     dfs_1(1);
122     dfs_2(1,1);
123     T.build(1,n,1);
124     while (m--){
125         int x,y,z;
126         scanf("%d",&x);
127         if (x==1){
128             scanf("%d %d",&y,&z);
129             T.update(w[y],w[y],z,1,n,1);
130         }
131         if (x==2){
132             scanf("%d %d",&y,&z);
133             T.update(w[y],w[y]+size[y]-1,z,1,n,1);
134         }
135         if (x==3){
136             scanf("%d",&y);
137             change(1,y);
138         }
139     }
140 }
View Code

 

  

posted @ 2016-08-01 23:04  rpSebastian  阅读(192)  评论(0编辑  收藏  举报