bzoj 3730
和上一题很像,而且这题直接给出了单点修改和区间查询,所以还是两棵线段树容斥即可
#include <cstdio> #include <cmath> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #include <queue> #include <stack> using namespace std; const int inf=0x3f3f3f3f; struct Edge { int next; int to; }edge[200005]; struct Segtree { int tot; int rot[100005]; int lson[15000005]; int rson[15000005]; int v[15000005]; void update(int &rt,int lq,int rq,int qx,int w) { if(!rt)rt=++tot; v[rt]+=w; if(lq==rq)return; int mid=(lq+rq)>>1; if(qx<=mid)update(lson[rt],lq,mid,qx,w); else update(rson[rt],mid+1,rq,qx,w); } int query(int rt,int lq,int rq,int ql,int qr) { if(!rt)return 0; if(lq>=ql&&rq<=qr)return v[rt]; int mid=(lq+rq)>>1; int ret=0; if(ql<=mid)ret+=query(lson[rt],lq,mid,ql,qr); if(qr>mid)ret+=query(rson[rt],mid+1,rq,ql,qr); return ret; } }tree1,tree2; int head[100005]; int n,m; int cnt=1; int f[100005]; int dep[100005]; int siz[100005]; int maxp[100005]; int pre[100005]; bool vis[100005]; int v0[100005]; int huge[100005]; int son[100005]; int ttop[100005]; int rt,s; inline int read() { int f=1,x=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void init() { memset(head,-1,sizeof(head)); cnt=1; } void add(int l,int r) { edge[cnt].next=head[l]; edge[cnt].to=r; head[l]=cnt++; } void dfs(int x,int fx) { huge[x]=1; f[x]=fx; dep[x]=dep[fx]+1; for(int i=head[x];i!=-1;i=edge[i].next) { int to=edge[i].to; if(to==fx)continue; dfs(to,x); huge[x]+=huge[to]; if(huge[to]>huge[son[x]])son[x]=to; } } void redfs(int x,int tp) { ttop[x]=tp; if(!son[x])return; redfs(son[x],tp); for(int i=head[x];i!=-1;i=edge[i].next) { int to=edge[i].to; if(to==son[x]||to==f[x])continue; redfs(to,to); } } int LCA(int x,int y) { while(ttop[x]!=ttop[y]) { if(dep[ttop[x]]>dep[ttop[y]])swap(x,y); y=f[ttop[y]]; } return dep[x]<dep[y]?x:y; } int get_dis(int x,int y) { return dep[x]+dep[y]-2*dep[LCA(x,y)]; } void get_rt(int x,int fa) { siz[x]=1,maxp[x]=0; for(int i=head[x];i!=-1;i=edge[i].next) { int to=edge[i].to; if(vis[to]||to==fa)continue; get_rt(to,x); siz[x]+=siz[to],maxp[x]=max(maxp[x],siz[to]); } maxp[x]=max(maxp[x],s-siz[x]); if(maxp[x]<maxp[rt])rt=x; } void solve(int x) { vis[x]=1; for(int i=head[x];i!=-1;i=edge[i].next) { int to=edge[i].to; if(vis[to])continue; rt=0,maxp[rt]=inf,s=siz[to]; get_rt(to,0); pre[rt]=x; solve(rt); } } int main() { n=read(),m=read(); init(); for(int i=1;i<=n;i++)v0[i]=read(); for(int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); add(x,y),add(y,x); } dfs(1,1); redfs(1,1); maxp[rt]=s=n; get_rt(1,0); solve(rt); for(int i=1;i<=n;i++) { int p=i,las=0; while(p) { int d=get_dis(p,i); tree1.update(tree1.rot[p],0,n,d,v0[i]); if(las)tree2.update(tree2.rot[las],0,n,d,v0[i]); las=p,p=pre[p]; } } int lastans=0; while(m--) { int typ=read(); if(typ) { int x=read()^lastans,temp=read()^lastans; int w=temp-v0[x]; v0[x]=temp; int p=x,las=0; while(p) { int d=get_dis(x,p); tree1.update(tree1.rot[p],0,n,d,w); if(las)tree2.update(tree2.rot[las],0,n,d,w); las=p,p=pre[p]; } }else { int x=read()^lastans,k=read()^lastans; int ans=0; int p=x,las=0; while(p) { int d=k-get_dis(x,p); if(d>=0) { ans+=tree1.query(tree1.rot[p],0,n,0,d); if(las)ans-=tree2.query(tree2.rot[las],0,n,0,d); } las=p,p=pre[p]; } printf("%d\n",ans); lastans=ans; } } return 0; }