【JZOJ 5992】万家灯火

13 篇文章 0 订阅
7 篇文章 0 订阅

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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值