在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i]。
不幸的是,这片土地常常发生地震,并且随着时代的发展,城市的价值也往往会发生变动。
接下来你需要在线处理M次操作:
0 x k 表示发生了一次地震,震中城市为x,影响范围为k,所有与x距离不超过k的城市都将受到影响,该次地震造成的经济损失为所有受影响城市的价值和。
1 x y 表示第x个城市的价值变成了y。
为了体现程序的在线性,操作中的x、y、k都需要异或你程序上一次的输出来解密,如果之前没有输出,则默认上一次的输出为0。
第一行包含两个正整数N和M。
第二行包含N个正整数,第i个数表示value[i]。
接下来N-1行,每行包含两个正整数u、v,表示u和v之间有一条无向边。
接下来M行,每行包含三个数,表示M次操作。
包含若干行,对于每个询问输出一行一个正整数表示答案。
这道题是动态树分治的模板题。
先建出分治树,每次修改和查询都在这个节点在分治树到根的路径上的所有祖先上面进行操作。
对每一个节点开2棵线段树,保存分治树上这个节点子树的信息。
于是就搞定啦!
代码:
#include
#include
using namespace std;
const int N=200005;
int n,m,op,u,v,cnt,idx,tot,ans,Log2[N*2],a[N],head[N],to[N*2],nxt[N*2],dfn[N],dep[N],siz[N],pos[N*2],f[N*2][25];
int rt,mi,size,fa[N],root[N][2],sumv[N*50],ch[N*50][2],dd[N];
bool vis[N];
void adde(int u,int v){
to[++cnt]=v;
nxt[cnt]=head[u];
head[u]=cnt;
}
void dfs(int pre,int u){
dfn[u]=++idx;
pos[idx]=u;
siz[u]=1;
int v;
for(int i=head[u];i;i=nxt[i]){
v=to[i];
if(v!=pre){
dep[v]=dep[u]+1;
dfs(u,v);
siz[u]+=siz[v];
pos[++idx]=u;
}
}
}
void st(){
for(int i=1;i<=idx;i++){
f[i][0]=pos[i];
}
for(int j=1;j<=20;j++){
for(int i=1;i+(1<1<=idx;i++){
if(dep[f[i][j-1]]1<<(j-1))][j-1]]){
f[i][j]=f[i][j-1];
}else{
f[i][j]=f[i+(1<<(j-1))][j-1];
}
}
}
}
int lca(int u,int v){
if(dfn[u]>dfn[v]){
swap(u,v);
}
int k=Log2[dfn[v]-dfn[u]];
if(dep[f[dfn[u]][k]]1<1][k]]){
return f[dfn[u]][k];
}else{
return f[dfn[v]-(1<1][k];
}
}
int dis(int u,int v){
return dep[u]+dep[v]-2*dep[lca(u,v)];
}
void upd(int &o,int l,int r,int k,int v){
if(kr){
return;
}
if(!o){
o=++tot;
}
sumv[o]+=v;
if(l==r){
return;
}
int mid=(l+r)/2;
if(k<=mid){
upd(ch[o][0],l,mid,k,v);
}else{
upd(ch[o][1],mid+1,r,k,v);
}
}
int qry(int o,int l,int r,int L,int R){
if(!o||L>r){
return 0;
}
if(L==l&&R==r){
return sumv[o];
}
int mid=(l+r)/2;
if(R<=mid){
return qry(ch[o][0],l,mid,L,R);
}else if(L>mid){
return qry(ch[o][1],mid+1,r,L,R);
}else{
return qry(ch[o][0],l,mid,L,mid)+qry(ch[o][1],mid+1,r,mid+1,R);
}
}
void dfsroot(int pre,int u){
siz[u]=1;
int v,mx=0;
for(int i=head[u];i;i=nxt[i]){
v=to[i];
if(!vis[v]&&v!=pre){
dfsroot(u,v);
siz[u]+=siz[v];
mx=max(mx,siz[v]);
}
}
mx=max(mx,size-siz[u]);
if(mxvoid init(int rt,int md,int pre,int u){
upd(root[rt][md],0,n,dd[u],a[u]);
int v;
for(int i=head[u];i;i=nxt[i]){
v=to[i];
if(!vis[v]&&v!=pre){
dd[v]=dd[u]+1;
init(rt,md,u,v);
}
}
}
void dfstree(int u){
vis[u]=true;
int v;
dd[u]=0;
init(u,0,0,u);
for(int i=head[u];i;i=nxt[i]){
v=to[i];
if(!vis[v]){
mi=size=siz[v];
dd[v]=1;
dfsroot(u,v);
init(rt,1,u,v);
fa[rt]=u;
dfstree(rt);
}
}
}
int query(int u,int d){
int ans=qry(root[u][0],0,n,0,d),tmp;
for(int i=u;fa[i];i=fa[i]){
tmp=dis(fa[i],u);
ans+=qry(root[fa[i]][0],0,n,0,d-tmp)-qry(root[i][1],0,n,0,d-tmp);
}
return ans;
}
void update(int u,int k){
int tmp;
upd(root[u][0],0,n,0,k-a[u]);
for(int i=u;fa[i];i=fa[i]){
tmp=dis(fa[i],u);
upd(root[fa[i]][0],0,n,tmp,k-a[u]);
upd(root[i][1],0,n,tmp,k-a[u]);
}
a[u]=k;
}
int main(){
for(int i=2;i<=200000;i++){
Log2[i]=Log2[i/2]+1;
}
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=1;iscanf("%d%d",&u,&v);
adde(u,v);
adde(v,u);
}
dfs(0,1);
st();
size=mi=siz[1];
dfsroot(0,1);
dfstree(rt);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&op,&u,&v);
u^=ans;
v^=ans;
if(op==0){
printf("%d\n",ans=query(u,v));
}else{
update(u,v);
}
}
return 0;
}