HDU3966 Aragorn's Story 树链剖分

题意:给你一棵树,每个节点有一个值,3种操作

1)Q  u询问  某一个点的值。

2)I  u v  w   把u,v之间(包括u,v)所有的点的值都加上 w 

3) D u v w  把u,v之间(包括u,v)所有的点的值都减去 w 

解题思路:树链剖分,树状数组记录改变值要比线段树快一点。

解题代码:

  1 // File Name: 3966.2.cpp
  2 #pragma comment(linker, "/STACK:1024000000,1024000000")
  3 // Author: darkdream
  4 // Created Time: 2015年04月14日 星期二 11时01分25秒
  5 
  6 #include<vector>
  7 #include<list>
  8 #include<map>
  9 #include<set>
 10 #include<deque>
 11 #include<stack>
 12 #include<bitset>
 13 #include<algorithm>
 14 #include<functional>
 15 #include<numeric>
 16 #include<utility>
 17 #include<sstream>
 18 #include<iostream>
 19 #include<iomanip>
 20 #include<cstdio>
 21 #include<cmath>
 22 #include<cstdlib>
 23 #include<cstring>
 24 #include<ctime>
 25 #define LL long long
 26 #define maxn 50005
 27 using namespace std;
 28 int sz[maxn];
 29 int fa[maxn];
 30 int son[maxn];
 31 int top[maxn];
 32 int dep[maxn];
 33 int w[maxn];
 34 int totw;
 35 vector<int> mp[maxn];
 36 int tr[maxn];
 37 int val[maxn];
 38 int lowbit(int x)
 39 {
 40   return x & -x; 
 41 }
 42 int n; 
 43 void update(int x, int uv){
 44     //printf("%d %d
",x,uv);
 45     while(x <= n + 1){
 46         tr[x] += uv;
 47         x += lowbit(x);
 48     }
 49 }
 50 int getsum(int x){
 51     int sum = 0 ; 
 52     while(x >= 1)
 53     {
 54        sum += tr[x];
 55        x -= lowbit(x);
 56     }
 57     return sum ;
 58 }
 59 
 60 void dfs_1(int k,int la,int d){
 61     int num = mp[k].size();
 62     dep[k] = d; 
 63     fa[k] = la ; 
 64     sz[k] = 1; 
 65     son[k] = -1;
 66     for(int i = 0 ;i < num ;i ++){
 67         if(mp[k][i] != la){
 68             dfs_1(mp[k][i],k,d+1);
 69             sz[k] += sz[mp[k][i]];
 70             if(son[k] == -1 || sz[mp[k][i]] > sz[son[k]])
 71                 son[k] = mp[k][i];
 72         }
 73     }
 74 }
 75 void dfs_2(int k ,int sp)
 76 {
 77    top[k] = sp ; 
 78    if(son[k] != -1){
 79        w[k] = ++ totw ;
 80        dfs_2(son[k],sp);
 81    }else{ 
 82        w[k] = ++totw;
 83        return ;
 84    }
 85    int num = mp[k].size(); 
 86    for(int i = 0 ;i < num ;i ++){
 87         if(mp[k][i] != son[k] && mp[k][i] != fa[k]){
 88             dfs_2(mp[k][i],mp[k][i]);
 89         }
 90    }
 91 }
 92 void make(){
 93     totw = 0 ; 
 94     memset(tr,0,sizeof(tr));
 95     dfs_1(1,0,1);
 96     dfs_2(1,1);
 97 }
 98 void find(int u ,int v,  int uv){
 99     int f1 = top[u],f2= top[v];
100     int tmp = 0 ; 
101     while(f1 != f2){
102         if(dep[f1] < dep[f2])
103         {
104             swap(u,v);
105             swap(f1,f2);
106         }
107         update(w[f1],uv);
108         update(w[u]+1,-uv);
109         u = fa[f1];
110         f1 = top[u];
111     }
112     if(dep[u] > dep[v]){    
113         swap(u,v);
114     }
115     update(w[u],uv);
116     update(w[v]+1,-uv);
117 }//不停的更新u,v,一直到在同一条链上
118 int main(){
119     int m , q; 
120     while(scanf("%d %d %d",&n,&m,&q) != EOF){
121         for(int i = 1;i <= n;i ++)
122             mp[i].clear();
123         for(int i = 1;i <= n;i ++)
124             scanf("%d",&val[i]);
125         int u,v; 
126         for(int i = 1;i < n;i ++){
127             scanf("%d %d",&u,&v);
128             mp[v].push_back(u);
129             mp[u].push_back(v);
130         }
131         make();
132         char op[10];
133         while(q--)
134         {
135             scanf("%s",op);
136             if(op[0] == 'Q'){
137                 scanf("%d",&v);
138                 printf("%d
",val[v] + getsum(w[v]));
139                 continue;
140             }
141             int add; 
142             scanf("%d %d %d",&u,&v,&add);
143             if(op[0] == 'I')
144                 find(u,v,add);
145             else find(u,v,-add);
146         }
147     }
148 return 0;
149 }
View Code
原文地址:https://www.cnblogs.com/zyue/p/4425041.html