首页 > 代码库 > hdu 4918

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

 

hdu 4918