Description
给定一棵N(N<=1e5)个点树,每个点有0/1的权值,有M(M<=1e5)次操作
1 x表示将x点的权值xor 1
2 x d表示查询与x点距离不超过d的点集中的连通块数,其中两个点之间右边当且仅当这两个点权值都为1,特别地x点与任何点没有边相连
Analysis
0->白,1->黑
连通块数=点数-边数
动态点分治+树状数组维护各个深度的黑点数/黑边数
一个tricky的地方是,假设当前有分治中心root,u为root的某个直接儿子且我们查询点x在u的子树内,则(u,root)这条边对答案的贡献需要特判
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<assert.h>
#define fo(i,a,b) for(int i=(a);i<=(b);++i)
#define fd(i,b,a) for(int i=(b);i>=(a);--i)
#define bfo(i,v,u) for(int i=BB[v],u=B[i][1];i;u=B[i=B[i][0]][1])
#define mset(a,x) memset(a,x,sizeof(a))
#define mcpy(a,b) memcpy(a,b,sizeof(b))
template<typename T> bool chkmin(T &a,const T &b) {return b<a?a=b,1:0;}
template<typename T> bool chkmax(T &a,const T &b) {return b>a?a=b,1:0;}
using namespace std;
typedef long long ll;
char ch;
int read(){int n=0,p=1;for(ch=getchar();ch<'0' || ch>'9';ch=getchar())if(ch=='-') p=-1;for(;'0'<=ch && ch<='9';ch=getchar()) n=n*10+ch-'0';return n*p;}
const int N=2e5+5;
int n,a[N],B0,BB[N],B[N<<1][2];
void link(int u,int v){B[++B0][1]=v,B[B0][0]=BB[u],BB[u]=B0;}
int sz,rt,mxd[N],now,st[N],now2,mxd2[N][20],st2[N][20],pa[N][20],dep[N][20],fa[N][20],g[N][20],be[N][20];
struct node
{
int x,y;
friend node operator + (const node &a,const node &b) {return (node){a.x+b.x,a.y+b.y};}
void operator += (const node &b) {*this = *this + b;}
friend node operator - (const node &a,const node &b) {return (node){a.x-b.x,a.y-b.y};}
void operator -= (const node &b) {*this = *this - b;}
}c[N],tr[N*20],c2[N],T2[N*20];
void add(int v,int x,node p)
{
if(x<0 || x>mxd[v]) return;
for(int i=1+x;i<=1+mxd[v];i+=(i&-i))
tr[st[v]+i] += p;
}
node query(int v,int x)
{
if(x<0) return (node){0,0};
chkmin(x,mxd[v]);
node res = (node){0,0};
for(int i=1+x;i;i-=(i&-i))
res += tr[st[v]+i];
return res;
}
void C2(int v,int D,int x,node p)
{
if(x<0 || x>mxd2[v][D]) return;
for(int i=1+x;i<=1+mxd2[v][D];i+=(i&-i))
T2[st2[v][D]+i] += p;
}
node Q2(int v,int D,int x)
{
if(x<0) return (node){0,0};
chkmin(x,mxd2[v][D]);
node res = (node){0,0};
for(int i=1+x;i;i-=(i&-i))
res += T2[st2[v][D]+i];
return res;
}
bool bz[N];
void getsz(int v,int fr=0)
{
++sz;
bfo(i,v,u) if(u!=fr && !bz[u]) getsz(u,v);
}
int getrt(int v,int fr=0)
{
int s=1;
bfo(i,v,u) if(u!=fr && !bz[u]) s+=getrt(u,v);
if(s+s>=sz && !rt) rt=v;
return s;
}
void dfs(int v,int fr,int src,int d,int D)
{
chkmax(mxd[rt],d),pa[v][D]=rt,dep[v][D]=d,fa[v][D]=fr,be[v][D]=src;
g[fr][D] += a[v];
c[d] += (node) {a[v],a[v] & a[fr]};
chkmax(mxd2[src][D],d);
c2[d] += (node) {a[v],a[v] & a[fr]};
bfo(i,v,u) if(u!=fr && !bz[u])
{
dfs(u,v,src,d+1,D);
}
}
void divide(int v,int D=1)
{
sz=0;getsz(v);
rt=0;getrt(v);
int root=rt;bz[rt]=1;
st[rt]=++now;
c[0]=(node){a[rt],0};//c[st[v]+j]=c[v][j]
pa[rt][D]=rt,dep[rt][D]=0,fa[rt][D]=0;
bfo(i,rt,u) if(!bz[u])
{
st2[u][D]=++now2;
dfs(u,rt,u,1,D);
C2(u,D,1,(node) {0,-(a[u] & a[rt])});
fo(j,1,mxd2[u][D])
C2(u,D,j,c2[j]),c2[j] = (node){0,0};
now2+=mxd2[u][D]+1;
}
fo(i,0,mxd[rt])
add(rt,i,c[i]),c[i] = (node){0,0};
now+=mxd[rt]+1;
bfo(i,root,u) if(!bz[u]) divide(u,D+1);
}
void change(int x)
{
fd(j,19,1) if(pa[x][j])
{
add(pa[x][j],dep[x][j],(node){(a[x]^1) - a[x],((a[x]^1) & a[fa[x][j]]) - (a[x] & a[fa[x][j]])});
add(pa[x][j],dep[x][j]+1,(node){0,a[x] ? -g[x][j] : g[x][j]});
if(be[x][j])
{
node t = (node){(a[x]^1) - a[x], (be[x][j]!=x) * (((a[x]^1) & a[fa[x][j]]) - (a[x] & a[fa[x][j]]))};
C2(be[x][j],j,dep[x][j],t);
C2(be[x][j],j,dep[x][j]+1,(node){0,a[x] ? -g[x][j] : g[x][j]});
}
if(fa[x][j]) g[fa[x][j]][j] += (a[x]^1) - a[x];
}
a[x]^=1;
}
int main()
{
freopen("lights.in","r",stdin);
freopen("lights.out","w",stdout);
n=read();int Q=read(),x,y;
fo(i,1,n-1) x=read(),y=read(),link(x,y),link(y,x);
fo(i,1,n)
{
for(ch=getchar();ch!='0' && ch!='1';ch=getchar());
a[i]=ch-'0';
}
divide(1);
while(Q--)
{
int tp=read(),x=read();
if(tp==1)
{
change(x);
}
else
{
bool p=0;
if(a[x]) change(x),p=1;
node ans = (node){0,0};
int d=read();
fd(j,19,1) if(pa[x][j])
{
ans += query(pa[x][j], d - dep[x][j]);
if(pa[x][j] != x)
ans -= Q2(be[x][j], j, d - dep[x][j]);
if(dep[x][j] == d) ans += (node) {0,a[be[x][j]] & a[pa[x][j]]};
}
printf("%d\n",ans.x-ans.y);
if(p) change(x);
}
}
return 0;
}