题目描述:
在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i]。
接下来你需要在线处理M次操作:
0 x k 表示发生了一次地震,震中城市为x,影响范围为k,所有与x距离不超过k的城市都将受到影响,该次地震造成的经济损失为所有受影响城市的价值和。
1 x y 表示第x个城市的价值变成了y。
为了体现程序的在线性,操作中的x、y、k都需要异或你程序上一次的输出来解密,如果之前没有输出,则默认上一次的输出为0。
1<=N,M<=100000,1<=value[i],y<=10000
题目分析:
动态点分治,在每个点分中心开一个树状数组维护子树中距离对应的权值和,另开一个树状数组维护子树中对点分树上父亲的贡献。(树状数组用指针开内存)
没怎么写动态点分治,有几个需要注意的地方:
- O(1)求LCA的ST表的大小要开 2 n 2n 2n,倍增的循环边界也是 2 n 2n 2n
- 由于要在当前点分中心的儿子上存它对自己的贡献,而当前并不知道子树内的重心是哪个点,所以要开一个临时数组存下对应子树需要维护的信息,再进入子树中,最后返回子树重心后将临时数组的值赋给它。
- 注意爬父亲的时候求的始终是一开始的 x x x到当前点分中心的距离,而不是两个相邻点分中心的距离。
- x x x与当前点分中心的距离如果超过了 k k k, x x x与更上面的点分中心的距离并不一定超过 k k k。
Code:
#include<bits/stdc++.h>
#define maxn 100005
using namespace std;
char cb[1<<18],*cs,*ct;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<18,stdin),cs==ct)?0:*cs++)
inline void read(int &a){
char c;while(!isdigit(c=getc()));
for(a=c-'0';isdigit(c=getc());a=a*10+c-'0');
}
const int Log = 17;
int n,m,w[maxn],dep[maxn],dfn[maxn],st[maxn<<1][Log+1],lg[maxn<<1],cnt;
int D[maxn],S[maxn],tp,siz[maxn],fa[maxn],ans;
bool vis[maxn];
int fir[maxn],nxt[maxn<<1],to[maxn<<1],tot;
inline void line(int x,int y){nxt[++tot]=fir[x],fir[x]=tot,to[tot]=y;}
int arr[maxn*40],*idx=arr;
struct BIT{
int *a,len;
void upd(int i,int v){for(;i<=len;i+=i&-i) a[i]+=v;}
int qsum(int i){int s=0;for(i=min(i,len);i;i-=i&-i) s+=a[i];return s;}
}A[maxn],B[maxn];
void dfs1(int u,int ff){
st[dfn[u]=++cnt][0]=dep[u]=dep[ff]+1;
for(int i=fir[u],v;i;i=nxt[i]) if((v=to[i])!=ff)
dfs1(v,u),st[++cnt][0]=dep[u];
}
inline int Dist(int x,int y){
int ret=dep[x]+dep[y];
if((x=dfn[x])>(y=dfn[y])) swap(x,y);
int k=lg[y-x+1];
return ret-2*min(st[x][k],st[y-(1<<k)+1][k]);
}
void getroot(int u,int ff,int tsz,int &g){
siz[u]=1; bool flg=1;
for(int i=fir[u],v;i;i=nxt[i]) if(!vis[v=to[i]]&&v!=ff)
getroot(v,u,tsz,g),siz[u]+=siz[v],flg&=siz[v]<<1<=tsz;
if(flg&&(tsz-siz[u])<<1<=tsz) g=u;
}
void dfs2(int u,int ff,int &mxd){
mxd=max(mxd,D[u]=D[ff]+1),S[++tp]=u;
for(int i=fir[u],v;i;i=nxt[i]) if(!vis[v=to[i]]&&v!=ff) dfs2(v,u,mxd);
}
int TDC(int u,int tsz){
getroot(u,0,tsz,u),vis[u]=1;
tp=0,dfs2(u,0,A[u].len),A[u].a=idx,idx+=A[u].len+1;
for(int i=1;i<=tp;i++) A[u].upd(D[S[i]],w[S[i]]);//D+1, qry's d+1.
BIT tmp;//!!!
for(int i=fir[u],v,x;i;i=nxt[i]) if(!vis[v=to[i]]){
tp=tmp.len=0,dfs2(v,u,tmp.len),tmp.a=idx,idx+=tmp.len+1;
for(int j=1;j<=tp;j++) tmp.upd(D[S[j]],w[S[j]]);
x=TDC(v,siz[v]<siz[u]?siz[v]:tsz-siz[u]);
fa[x]=u,B[x]=tmp;
}
return u;
}
void modify(int x,int v){
int delta=v-w[x]; w[x]=v;
A[x].upd(1,delta);
for(int i=x,d;fa[i];i=fa[i])//attention to the d.
d=Dist(fa[i],x),A[fa[i]].upd(d+1,delta),B[i].upd(d+1,delta);
}
void solve(int x,int k){
ans=A[x].qsum(k+1);
for(int i=x,d;fa[i];i=fa[i]){
if((d=Dist(fa[i],x))>k) continue;//!!! not return!!!
ans+=A[fa[i]].qsum(k-d+1)-B[i].qsum(k-d+1);
}
}
int main()
{
int x,y,op;
read(n),read(m);
for(int i=1;i<=n;i++) read(w[i]);
for(int i=1;i<n;i++) read(x),read(y),line(x,y),line(y,x);
dfs1(1,0),lg[0]=-1;
for(int i=1;i<=cnt;i++) lg[i]=lg[i>>1]+1;
for(int j=1;j<=Log;j++) for(int i=1;i+(1<<j)-1<=cnt;i++) st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
TDC(1,n);
while(m--){
read(op),read(x),read(y),x^=ans,y^=ans;
if(!op) solve(x,y),printf("%d\n",ans);
else modify(x,y);
}
}