1. 程式人生 > >cf 1076e 樹上差分+樹狀陣列+離線

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; }