hdu 4918

一道比较好的树分治的题目.大力推荐~

Query on the subtree

Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 479    Accepted Submission(s): 163


Problem Description
bobo has a tree, whose vertices are conveniently labeled by 1,2,…,n. At the very begining, the i-th vertex is assigned with weight wi.

There are q operations. Each operations are of the following 2 types:

Change the weight of vertex v into x (denoted as "! v x"),
Ask the total weight of vertices whose distance are no more than d away from vertex v (denoted as "? v d").

Note that the distance between vertex u and v is the number of edges on the shortest path between them.
 

 

Input
The input consists of several tests. For each tests:

The first line contains n,q (1≤n,q≤105). The second line contains n integers w1,w2,…,wn (0≤wi≤104). Each of the following (n - 1) lines contain 2 integers ai,bi denoting an edge between vertices ai and bi (1≤ai,bi≤n). Each of the following q lines contain the operations (1≤v≤n,0≤x≤104,0≤d≤n).
 

 

Output
For each tests:

For each queries, a single number denotes the total weight.
 

 

Sample Input
4 3
1 1 1 1
1 2
2 3
3 4
? 2 1
! 1 0
? 2 1
3 3
1 2 3
1 2
1 3
? 1 0
? 1 1
? 1 2
 
Sample Output
3
2
1
6
6
 
题目大意:
  给出一棵树,边权均为1,有两种操作,改变某个点的权值,求距离某个点的距离不超过k的点的权值和.
 
思路:
  这种动态的树分治问题我们应该这么想.
  想办法维护这个分治的结构,让它修改的速度变得快一些....
 
  于是我们这样子做.
  按照无修改的思路.我们要先全局计算,然后再减掉单独的子树内的重复信息.
  不难想到用树状数组来解决这个问题.
  为了方便找到全局和子树内的信息,每个点要维护两个树状数组.
  一个是这个点的子树内的信息,另外一个是这个点的子树内的点到上一层的中心点中的距离.
  这样我们就能在O(nlog2n)的时间内完成对一次询问的回答.
  然后注意.这个做法的复杂度的保证是基于两个中心点之间的距离的距离是O(logn)的.
  在另外一篇博文上吧这个做法称之为"重心树"还是蛮恰当的.
 
  我的程序参考了那篇博文的标程....凑合着看吧.
  Ps:一个大惑不解的问题.两个差不多的程序,为什么一个爆栈了呢?
  
  1 #include<cstdlib>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<vector>
  6 #include<cctype>
  7 using namespace std;
  8 const int maxn = (int)3e5, inf = 0x3f3f3f3f;
  9 struct E{
 10     int t,w,last;
 11 }e[maxn * 4];
 12 struct EE{
 13     int rt,srt,dis,last;
 14 }ee[maxn * 6];
 15 int ll[maxn * 6],edge;
 16 int last[maxn * 4],edg;
 17 int n,q;
 18 inline int getint(){
 19     int ret = 0; char ch = getchar();
 20     while(!isdigit(ch)) ch = getchar();
 21     while(isdigit(ch)) ret = ret * 10 + ch - '0', ch = getchar();
 22     return ret;
 23 }
 24 inline void add2(int x,int rt,int srt,int dis){
 25     ee[++edge] = (EE){rt,srt,dis,ll[x]}; ll[x] = edge;
 26 }
 27 inline void add(int x,int y,int w){
 28     e[++edg] = (E){y,w,last[x]}; last[x] = edg;
 29     e[++edg] = (E){x,w,last[y]}; last[y] = edg;
 30 }
 31 int w[maxn];
 32 int vis[maxn];
 33 int sz[maxn],tmax,node,root;
 34 void getroot(int x,int fa){
 35     sz[x] = 0;
 36     int Max = 0;
 37     for(int i = last[x]; i; i = e[i].last)
 38         if(!vis[e[i].t] && e[i].t != fa){
 39             getroot(e[i].t, x);
 40             sz[x] += sz[e[i].t] + 1;
 41             Max = max(Max, sz[e[i].t] + 1);
 42         }
 43     Max = max(Max, node - sz[x] - 1);
 44     if(tmax > Max) tmax = Max, root = x;
 45 }
 46 struct BIT{
 47     vector<int>v;
 48     void init(int sz){
 49         v.clear(); v.resize(sz + 2);
 50     }
 51     inline int lowbit(int x){
 52         return x & (-x);
 53     }    
 54     void add(int pos,int val){
 55         for(++pos; pos < (int)v.size(); pos += lowbit(pos)) v[pos] += val;
 56     }
 57     int qer(int pos){
 58         pos = min(pos + 1, (int)v.size() - 1);
 59         int ret = 0;
 60         for(; pos > 0; pos -= lowbit(pos)) ret += v[pos];
 61         return ret;
 62     }
 63 }T[maxn * 3];
 64 int cur;
 65 int rt,srt,dist;
 66 void getdata(int pt,int k, int x, int fa, int dis){
 67     if(k) add2(x,k,pt,dis);
 68     T[pt].add(dis, w[x]);
 69     for(int i = last[x]; i; i = e[i].last)
 70         if(!vis[e[i].t] && e[i].t != fa)
 71             getdata(pt, k, e[i].t, x, dis + e[i].w);
 72 }
 73 void dfs(int x,int size){
 74     int p;
 75     T[p = ++cur].init(size);
 76     getdata(p, 0, x, 0, 0);
 77     add2(x, p, 0, 0);
 78     vis[x] = 1;
 79     for(int i = last[x]; i; i = e[i].last)
 80         if(!vis[e[i].t]){
 81             tmax = inf, node = sz[e[i].t];
 82             getroot(e[i].t, root = 0);
 83             T[++cur].init(sz[e[i].t] + 1);
 84             getdata(cur, p, e[i].t, 0, e[i].w);
 85             dfs(root,sz[e[i].t]);
 86         }
 87 }
 88 void work(){
 89     tmax = inf, node = n;
 90     getroot(1,root = 0);
 91     dfs(root,n);
 92 }
 93 void query(){
 94     int x = getint(), d = getint();
 95     int ret = 0;
 96     for(int i = ll[x]; i; i = ee[i].last){
 97         int rt = ee[i].rt, srt = ee[i].srt, dis = ee[i].dis;
 98         ret += T[rt].qer(d - dis);
 99         if(srt) ret -= T[srt].qer(d - dis);
100     }
101     printf("%d\n",ret);
102 }
103 void maintain(){
104     int x = getint(), ww = getint();
105     for(int i = ll[x]; i; i = ee[i].last){
106         int rt = ee[i].rt,srt = ee[i].srt,dis = ee[i].dis;
107         T[rt].add(dis, ww - w[x]);
108         if(srt) T[srt].add(dis, ww - w[x]);
109     }
110     w[x] = ww;
111 }
112 void solve(){
113     char op;
114     while(q--){
115         scanf("%c\n",&op);
116         if(op == '?') query();
117         else maintain();
118     }
119 }
120 void init(){
121     memset(vis,0,sizeof(vis));
122     memset(last,0,sizeof(last));
123     memset(ll,0,sizeof(ll));
124     cur = edge = edg = 0;
125 }
126 int main()
127 {
128     freopen("subtree.in","r",stdin);
129     freopen("subtree.out","w",stdout);
130     while(scanf("%d %d",&n,&q) != EOF){
131         for(int i = 1; i <= n; ++i) w[i] = getint();
132         for(int i = 1; i < n; ++i){
133             int u = getint(), v = getint();
134             add(u,v,1);
135         }
136         work();
137         solve();
138         init();
139     }
140     return 0;
141 }
View Code

 

posted @ 2015-01-10 19:52  Mr.Ren~  阅读(385)  评论(0编辑  收藏  举报