BZOJ3730: 震波
https://lydsy.com/JudgeOnline/problem.php?id=3730
分析:
- 对于点分树上的每个点(x),维护子树所有点到(x)的距离和到点分树上(fa[x])的距离 。
- 查询时查询(x)在点分树上到根的一条链,容斥计算答案。
- 然后因为有修改我们使用树状数组。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <vector>
#include <iostream>
using namespace std;
#define N 100050
char buf[100000],*p1,*p2;
#define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
int rd() {
int x=0;
char s=nc();
while(s<'0') s=nc();
while(s>='0') x=(((x<<2)+x)<<1)+s-'0',s=nc();
return x;
}
#define db(x) cerr<<#x<<" = "<<x<<endl
int head[N],to[N<<1],nxt[N<<1],cnt,n,m,val[N];
int siz[N],fk[N],root,tot,used[N],fa[N][20],dis[N][20],dep[N];
struct Bit {
vector<int>b;
void make(int s) {b.resize(s+2);}
void fix(int x,int v) {
x++;
int lim=b.size();
for(;x<lim;x+=x&(-x)) b[x]+=v;
}
int inq(int x) {
x++;
int re=0;
x=min(x,int(b.size())-1);
for(;x;x-=x&(-x)) re+=b[x];
return re;
}
}f1[N],f2[N];
inline void add(int u,int v) {
to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt;
}
void gr(int x,int y) {
int i;
siz[x]=1; fk[x]=0;
for(i=head[x];i;i=nxt[i]) if(to[i]!=y&&!used[to[i]]) {
gr(to[i],x); siz[x]+=siz[to[i]];
fk[x]=max(fk[x],siz[to[i]]);
}
fk[x]=max(fk[x],tot-siz[x]);
if(fk[root]>fk[x]) root=x;
}
int mxd;
void gd(int x,int y,int rt,int d) {
int i;
mxd=max(mxd,d);
for(i=head[x];i;i=nxt[i]) if(to[i]!=y&&!used[to[i]]) {
mxd=max(mxd,dis[to[i]][dep[to[i]]]);
fa[to[i]][++dep[to[i]]]=rt;
dis[to[i]][dep[to[i]]]=d;
gd(to[i],x,rt,d+1);
}
}
void solve(int x) {
used[x]=1;
int i;
mxd=0;
gd(x,0,x,1);
f1[x].make(mxd); f2[x].make(mxd);
int all=tot;
for(i=head[x];i;i=nxt[i]) if(!used[to[i]]) {
tot=siz[to[i]];
root=0; gr(to[i],x); solve(root);
}
}
void upd(int x,int v) {
int i;
f1[x].fix(0,v);
f2[x].fix(dis[x][dep[x]],v);
for(i=dep[x];i;i--) {
f1[fa[x][i]].fix(dis[x][i],v);
f2[fa[x][i]].fix(dis[x][i-1],v);
}
}
int query(int x,int k) {
int i,re=f1[x].inq(k);
for(i=dep[x];i;i--) {
if(k>=dis[x][i]) {
re+=f1[fa[x][i]].inq(k-dis[x][i]);
re-=f2[fa[x][i+1]].inq(k-dis[x][i]);
}
}
return re;
}
int main() {
n=rd(),m=rd();
int i,x,y,opt;
for(i=1;i<=n;i++) val[i]=rd();
for(i=1;i<n;i++) {
x=rd(), y=rd();
add(x,y); add(y,x);
}
tot=n;
fk[0]=1ll<<30;
gr(1,0);
solve(root);
for(i=1;i<=n;i++) fa[i][dep[i]+1]=i;
for(i=1;i<=n;i++) upd(i,val[i]);
int ans=0;
while(m--) {
opt=rd(), x=rd(), y=rd();
x^=ans, y^=ans;
if(!opt) {
ans=query(x,y);
printf("%d
",ans);
}else {
upd(x,y-val[x]), val[x]=y;
}
}
}