#4532 震波
题面
在一片土地上有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次操作。
输出
包含若干行,对于每个询问输出一行一个正整数表示答案。
样例输入
8 1
1 10 100 1000 10000 100000 1000000 10000000
1 2
1 3
2 4
2 5
3 6
3 7
3 8
0 3 1
样例输出
11100101
提示
1<=N,M<=100000
1<=u,v,x<=N
1<=value[i],y<=10000
0<=k<=N-1
SOL
DFS预处理
暴力跳fa,统计自己子树的答案并减去自己对fa的贡献
BIT维护val值——树状数组(或线段树)维护每一个分治中心的信息
空间可能爆,所以用vector
p.s.这里用ST表维护了一下dis
代码:
//- 输出大小: 1.32719135284424 MiB
#include<vector>
#include<cstdio>
#include<iostream>
using namespace std;
#define N 100005
#define ll long long
#define re register
inline int rd(){
int data=0ll,w=1ll;static char ch=0;ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')w=-1ll,ch=getchar();
while(ch>='0'&&ch<='9')data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
return data*w;
}
inline int lb(int x){return x&(-x);}
struct vec{
vector<int>v;int n;
inline void init(){v.assign(n+10,0);}
inline void update(int p,int k){
p++;
while(p<=n){
v[p]+=k;
p+=lb(p);
}//树状数组维护
}
inline int query(int p,int res=0){
p++;
p=min(p,n);//p might be larger than n,or smaller than 0
while(p>=1){
res+=v[p];
p-=lb(p);
}
return res;
}
}f1[N],f2[N];
int n,m,maxn,rt,cnt;
int siz[N],son[N],dep[N],fa[N],vis[N];
int first[N],nxt[N<<1],to[N<<1],val[N<<1];
int ecnt,d[N];
namespace ST{
int dis[N],dfn,pos[N],st[22][N<<2],lg[N<<2];
void dfs(int u,int f){
st[0][++dfn]=dis[u],pos[u]=dfn;
for(int re e=first[u];e;e=nxt[e]){
int re v=to[e];
if(v==f)continue;
dis[v]=dis[u]+1;
dfs(v,u);
st[0][++dfn]=dis[u];
}
}
void init(){
dfs(1,0),lg[0]=-1;
for(int re i=1;i<=dfn;i++)lg[i]=lg[i>>1]+1;
for(int re i=1;(1<<i)<=dfn;i++)
for(int re j=1;j+(1<<i)-1<=dfn;j++)
st[i][j]=min(st[i-1][j],st[i-1][j+(1<<(i-1))]);
}
inline int dist(int u,int v){
int re x=pos[u],y=pos[v];
if(x>y)swap(x,y);
int re t=lg[y-x+1];
return dis[u]+dis[v]-2*min(st[t][x],st[t][y-(1<<t)+1]);
}
}
using namespace ST;
inline void add(int u,int v){nxt[++cnt]=first[u];first[u]=cnt;to[cnt]=v;}
void getrt(int u,int f){
siz[u]=1;son[u]=0;
for(int re e=first[u];e;e=nxt[e]){
int re v=to[e];
if(v==f||vis[v])continue;
getrt(v,u),siz[u]+=siz[v];
son[u]=max(son[u],siz[v]);
}
son[u]=max(son[u],maxn-siz[u]);
if(son[u]<son[rt])rt=u;
}
void getdist(int u,int f){
d[dep[u]]+=val[u],ecnt=max(ecnt,dep[u]);
for(int re e=first[u];e;e=nxt[e]){
int re v=to[e];
if(v==f||vis[v])continue;
dep[v]=dep[u]+1;
getdist(v,u);
}
}
inline void calc(vec &tr){
tr.n=ecnt+1,tr.init();
for(int re i=0;i<=ecnt;i++){
tr.update(i,d[i]);
d[i]=0;
}ecnt=0;
}
void solve(int u){
vis[u]=1;
dep[u]=0;getdist(u,0);
calc(f1[u]);
for(int re e=first[u];e;e=nxt[e]){
int re v=to[e];
if(vis[v])continue;
son[0]=maxn=siz[v];
getrt(v,rt=0),fa[rt]=u;
dep[v]=1,getdist(v,0);
calc(f2[rt]),dep[v]=0;
solve(rt);
}
}
inline void update(int u,int k){
for(int re i=u;i;i=fa[i])f1[i].update(dist(i,u),k);
for(int re i=u;fa[i];i=fa[i])f2[i].update(dist(u,fa[i]),k);
}
inline int query(int u,int k){
int re res=0;
for(int re i=u;i;i=fa[i])res+=f1[i].query(k-dist(i,u));
for(int re i=u;fa[i];i=fa[i])res-=f2[i].query(k-dist(fa[i],u));
return res;
}
int last;
signed main(){
n=rd(),m=rd();
for(int re i=1;i<=n;i++)val[i]=rd();
for(int re i=1;i<n;i++){
int re u=rd(),v=rd();
add(u,v),add(v,u);
}init();
maxn=son[0]=n;
getrt(1,rt=0),solve(rt);
while(m--){
int op=rd(),u=rd()^last,k=rd()^last;
if(op==0)printf("%d\n",last=query(u,k));
else update(u,k-val[u]),val[u]=k;
}
return 0;
}