一道比较好的树分治的题目.大力推荐~
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 w
i.
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.
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≤10 5). The second line contains n integers w 1,w 2,…,w n (0≤w i≤10 4). Each of the following (n - 1) lines contain 2 integers a i,b i denoting an edge between vertices a i and b i (1≤a i,b i≤n). Each of the following q lines contain the operations (1≤v≤n,0≤x≤10 4,0≤d≤n).
The first line contains n,q (1≤n,q≤10 5). The second line contains n integers w 1,w 2,…,w n (0≤w i≤10 4). Each of the following (n - 1) lines contain 2 integers a i,b i denoting an edge between vertices a i and b i (1≤a i,b i≤n). Each of the following q lines contain the operations (1≤v≤n,0≤x≤10 4,0≤d≤n).
Output
For each tests:
For each queries, a single number denotes the total weight.
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(nlog
2n)的时间内完成对一次询问的回答.
然后注意.这个做法的复杂度的保证是基于两个中心点之间的距离的距离是O(logn)的.
在另外一篇博文上吧这个做法称之为"重心树"还是蛮恰当的.
我的程序参考了那篇博文的标程....凑合着看吧.
Ps:一个大惑不解的问题.两个差不多的程序,为什么一个爆栈了呢?
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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 }