cf 1076e 树上差分+树状数组+离线
http://codeforces.com/contest/1076/problem/E
参考博客:http://www.cnblogs.com/AKMer/p/9950332.html
题意:
根节点为1 树,m次操作,每次给定v,d,x,将v的儿子(包含其本身)与它距离<=d的权值加上x
问最后 所有节点的权值
思路:
离线操作
将m次操作保存,之后在dfs的时候用树状数组动态维护深度差分值
,然后单点询问当前深度应该增加多少就行了。如果本子树处理完了,那么就把差分去掉,以免影响其它子树。
注意:因为树状数组是以深度为基础的,所以对一个子树,其深度符合条件,就可以加上
然后这个子树访问完毕,在用树状数组反差分回去
开始数组忘了*2 居然给mle而不是re....
#include<bits/stdc++.h> using namespace std; #define ll long long #define pb push_back #define mp make_pair #define pii pair<int,int> #define fi first #define se second #define low(i) ((i)&(-i)) const int N = 3e5+3; int dep[N];int n; ll ans[N]; vector< pair<int,int > >qu[N]; vector< pair<int,int > >::iterator it; int y[N*2],fst[N],nxt[N*2]; int cnt; void addedge(int a,int b){ y[++cnt] =b; nxt[cnt] = fst[a]; fst[a] = cnt; } struct TreeArray { ll c[N]; void add(int pos,int v) { for(int i=pos;i<=n;i+=low(i)) c[i]+=v; } ll query(int pos) { ll res=0; for(int i=pos;i;i-=low(i)) res+=c[i]; return res; } }T; void dfs(int x,int pre){ dep[x] =dep[pre]+1; for(int i=fst[x];i;i=nxt[i]){ if(y[i]!=pre) dfs(y[i],x); } } void get(int pre,int x){ ////进来的时候差分 for( it = qu[x].begin();it!=qu[x].end();++it){ T.add(dep[x],(*it).se); //这里 是 r+1 T.add( min(n,dep[x]+(*it).fi)+1,-(*it).se); } ans[x] = T.query(dep[x]); for(int i=fst[x];i;i=nxt[i]){ if(y[i]!=pre)get(x,y[i]); } //出去的时候反差分 for( it = qu[x].begin();it!=qu[x].end();++it){ T.add(dep[x],-(*it).se); //这里 是 r+1 T.add( min(n,dep[x]+ (*it).fi)+1,(*it).se); } } int main(){ scanf("%d",&n); int v,u,m,d,x; for(int i=1;i<n;++i){ scanf("%d %d",&u,&v); addedge(u,v); addedge(v,u); } dfs(1,0); scanf("%d",&m); while(m--){ scanf("%d %d %d",&v,&d,&x); qu[v].push_back( mp(d,x)); } get(0,1); for(int i=1;i<=n;++i) printf("%lld ",ans[i]); return 0; }