搞了一晚上,错了,以后回头再来看
/* 对于每次更新,先处理其儿子方向,再处理其父亲方向 处理父亲方向时无法达到根,那么直接更新 如果能达到根,那么到兄弟链中去更新,使用bfs序 最后,查询结点v的结果就是dfs序线段树上的查询值+bfs线段树上的查询值 */ #include<iostream> #include<cstring> #include<vector> #include<queue> using namespace std; #define maxn 150005 int n,q; vector<int> mp[maxn]; struct node{ int u,depth; }now,nex; int depthL[maxn];//深度为i的下标最小的点 int depthR[maxn];//深度为i的下标最大的点 int num[maxn];//bfs序 int vis[maxn]; int L[maxn];//dfs入序 int R[maxn];//某结点为根的最大深度 int dist[maxn]; int cnt; void Dfs(int u,int from,int dis){ L[u]=++cnt; dist[u]=dis; for(int i=0;i<mp[u].size();i++){ int v=mp[u][i]; if(v==from) continue; Dfs(v,u,dis+1); } R[u]=cnt; } //处理bfs序的方法 void Bfs(){ int tot=0; queue<node>s; now.u=1,now.depth=0; s.push(now); memset(depthL,-1,sizeof depthL); memset(depthR,0,sizeof depthR); memset(vis,0,sizeof vis); vis[1]=1; while(!s.empty()){ tot++; now=s.front(); s.pop(); num[now.u]=tot; if(depthL[now.depth==-1]) depthL[now.depth]=num[now.u]; depthR[now.depth]=max(depthR[now.depth],num[now.u]); for(int i=0;i<mp[now.u].size();i++){ int v=mp[now.u][i]; if(vis[v]==0){ vis[v]=1; nex.u=v; nex.depth=now.depth+1; s.push(nex); } } } } //第一棵线段树处理dfs上的修改和查询,因为所有的子树都是链,其dfs连续,所以直接用线段树区间更新 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 int tree[maxn<<2]; int flag[maxn<<2]; inline void pushup(int rt){ tree[rt]=tree[rt<<1]+tree[rt<<1|1]; } inline void pushdown(int l,int r,int rt){ if(flag[rt]){ int m=l+r>>1; flag[rt<<1]+=flag[rt]; tree[rt<<1]=(m-l+1)*flag[rt]; tree[rt<<1|1]=(r-m)*flag[rt]; flag[rt]=0; } } void build(int l,int r,int rt){ tree[rt]=flag[rt]=0; if(l==r) return; int m=l+r>>1; pushdown(l,r,rt); build(lson); build(rson); pushup(rt); } void update(int L,int R,int c,int l,int r,int rt){ if(L<=l && R>=r){ tree[rt]+=(r-l+1)*c; flag[rt]+=c; return; } int m=l+r>>1; pushdown(l,r,rt); if(L<=m) update(L,R,c,lson); if(R>m) update(L,R,c,rson); pushup(rt); } //是单点查询 int query(int p,int l,int r,int rt){ if(l==r) return tree[rt]; int m=l+r>>1; pushdown(l,r,rt); if(p<=m) return query(p,lson); if(p>m) return query(p,rson); pushup(rt); } //第二棵线段树用来处理bfs上的修改和查询 //bfs序线段树也是通过访问顺序维护信息 int sum[maxn<<2]; int flag2[maxn<<2]; inline void pushup2(int rt){ sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } inline void pushdown2(int l,int r,int rt){ if(flag2[rt]){ int m=l+r>>1; flag2[rt>>1]+=flag2[rt]; flag2[rt>>1|1]+=flag2[rt]; sum[rt>>1]+=(m-l+1)*flag2[rt]; sum[rt>>1|1]+=(r-m)*flag2[rt]; flag2[rt]=0; } } void build2(int l,int r,int rt){ sum[rt]=flag2[rt]=0; if(l==r) return; int m=l+r>>1; pushdown2(l,r,rt); build(lson); build(rson); pushup2(rt); } void update2(int L,int R,int c,int l,int r,int rt){ if(L<=l && R>=r){ sum[rt]+=(r-l+1)*c; flag2[rt]+=c; return; } int m=l+r>>1; pushdown2(l,r,rt); if(L<=m) update(L,R,c,lson); if(R>m) update(L,R,c,rson); pushup2(rt); } int query2(int p,int l,int r,int rt){ if(l==r) return sum[rt]; int m=l+r>>1; pushdown2(l,r,rt); if(p<=m) return query2(p,lson); if(p>m) return query2(p,rson); pushup2(rt); } int main(){ while(scanf("%d%d",&n,&q)==2){ for(int i=1;i<=n;i++) mp[i].clear(); for(int i=1;i<=n-1;i++){ int x,y; scanf("%d%d",&x,&y); mp[x].push_back(y); mp[y].push_back(x); } cnt=0; Dfs(1,-1,0); Bfs(); build(1,n,1); build2(1,n,1); while(q--){ int op; scanf("%d",op); if(op==1){//查询结点x的值 int x; scanf("%d",&x); printf("%d\n",query(L[x],1,n,1)+query2(num[x],1,n,1)); } else { int u,v,d;scanf("%d%d%d",&u,&v,&d); if(u==1){//如果是根结点,直接在兄弟结点上更新 if(depthR[d]!=0)//这个深度是有节点的 update2(1,depthR[d],v,1,n,1); else //这个深度没有结点了,整棵树更新 update2(1,n,v,1,n,1); continue; } //如果不是根结点上更新 //先在dfs序上更新,注意 update(L[u],min(L[u]+d,R[u]),v,1,n,1); if(d<dist[u])//如果根到u距离大于d,直接在链上更新 update(L[u]-d,L[u]-1,v,1,n,1); else { //先从根维护到u的父亲 update(L[u]-(dist[u]-1),L[u]-1,v,1,n,1); update(L[u]-(dist[u]-1),min(L[u]-(dist[u]-1)+(d-dist[u]-1),R[u]),-v,1,n,1);//取消root到其兄弟结点相同深度的相应修改,因为接下去bfs序修改会重复 if(depthR[d-dist[u]]!=0)//如果这个深度有结点 update2(1,depthR[d-dist[u]],v,1,n,1); else update2(1,n,v,1,n,1); } } } } }