題意:一棵樹有n個節點,但是除了根節點1外,其他節點都的出度和入度加起來就只有2(就是棵樹是由幾條鏈的第一個節點粘在一起的),現在有兩種操作(1)"0 v x d",在距離v節點距離d以內的所有節點的權值都加上1,(2)"1 v",查詢節點v上的權值。
沒想到辦法靜態建樹,用vector<vector<LL> >去動態地建樹。
去掉根節點,對每條鏈建一個樹狀數組(表示這個鏈上的每個節點加了多少權值),然後另外加一個樹狀數組表示從根節點開始的,距離為1到n的節點加了多少權值,維護好這兩部分樹狀數組就可以了。
#include <iostream>#include <cstdio>#include <cstring>#include <vector>#include <map>using namespace std;typedef long long LL;const int N=1e5+5;int dis[N],fa[N];vector<int> adj[N];vector<vector<LL> > line;int lowbit(int x){return x&(-x);}void updata(int st,int ed,int valu,int id){ if(st>ed) return; int mx=(int)line[id].size(); for(int i=ed+1;i<mx;i+=lowbit(i)) line[id][i]-=valu; for(int i=st;i<mx;i+=lowbit(i)) line[id][i]+=valu;}LL query(int ind,int id){ LL sum=0; int mx=(int)line[id].size(); for(int i=ind;i>0;i-=lowbit(i)) sum+=line[id][i]; return sum;}void dfs(int u,int pre,int cnt,int id){ dis[u]=cnt; fa[u]=id; line[id].push_back(0); for(int i=0;i<(int)adj[u].size();i++) { int v=adj[u][i]; if(v==pre) continue; dfs(v,u,cnt+1,id); }}int main(){ int n,q; scanf("%d%d",&n,&q); for(int i=0;i<n-1;i++) { int a,b; scanf("%d%d",&a,&b); adj[a].push_back(b); adj[b].push_back(a); } int tot=(int)adj[1].size(); line.resize(tot+5); for(int i=0;i<(int)adj[1].size();i++) { line[i+1].push_back(0); dfs(adj[1][i],1,1,i+1); } line[0].resize(N,0); LL sum_root=0; while(q--) { int cmd; scanf("%d",&cmd); if(cmd==0) { int v,x,d; scanf("%d%d%d",&v,&x,&d); if(v==1) { sum_root+=x; updata(1,d,x,0); } else { int id=fa[v]; if(d<dis[v]) updata(dis[v]-d,dis[v]+d,x,id); else { sum_root+=x; updata(1,dis[v]+d,x,id); updata(1,d-dis[v],x,0); updata(1,d-dis[v],-x,id); } } } else { int v; scanf("%d",&v); if(v==1) printf("%I64d\n",sum_root); else { int id=fa[v]; // cout<<query(dis[v],id)<<" "<<query(dis[v],0)<<endl; LL ans=query(dis[v],id)+query(dis[v],0); printf("%I64d\n",ans); } } } return 0;}