联考20200718 T2 树论

题目描述:



分析:
人傻了,神仙码农题写半天调半天
首先要看出每个点SG函数的规律,就是该点到其子树内最远点的距离
理性分析一下,画图看看发现很有道理(
如果根是确定的,那么SG函数就确定,树链剖分+线段树反转操作维护每个点的石头数的奇偶性计算贡献
换根让题目变难了很多
首先有个结论,对于\(n\)种根,每个点SG函数的取值只会有2种

然后这个\(f\)\(g\),两次dfs就可以算出来
确定一个点为根,这样有的点SG函数是\(f\),有的是\(g\),搞起来很头疼
如果确定直径的中点为根,那么所有点的SG函数就都是\(g\)
\(f\)所属的路径必定经过直径中点(奥妙重重)
那么这个时候,我们从直径中点换根为\(x\)时,路径上的点的SG值都会变成\(f\)
只有中点本身需要分类讨论一下(有点恶心)
这个也相当于一个翻转操作,\(f\)\(g\)互换
那么线段树每个点维护\(2*2\)的矩阵,分行列两种翻转,可以维护
换根对于路径加石头不影响,对子树就会有影响
假设dfs维护出根为直径中点\(Rt\)的树,目前的根为\(rt\),要修改\(x\)\(rt\)为根下的子树
如果两者在以\(Rt\)为根的dfs序上不相交或者\(rt\)的子树区间包含\(x\),那么直接修改,否则(即\(x\)\(rt\)祖先)要变换一下:
如图:

我们找到【\(rt\)\(x\)的方向】\(p\),修改的区间其实是全区间除去\(p\)的子树区间
还有如果\(x\)就是\(rt\),那么修改的是全区间

树链剖分+线段树翻转操作复杂度\(O(nlog^2n)\)
恶心的细节很多

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<string>

#define maxn 500005
#define INF 0x3f3f3f3f

using namespace std;

inline int getint()
{
	int num=0,flag=1;char c;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
	return num*flag;
}

int n,m;
int fir[maxn],nxt[maxn],to[maxn],cnt;
int sz[maxn],fa[maxn],dpt[maxn],son[maxn],tp[maxn];
int pos[maxn],Id[maxn],cur;
struct node{
	int a[2][2];
	int R,C;
	inline void revC(){swap(a[0][0],a[0][1]),swap(a[1][0],a[1][1]),C^=1;}
	inline void revR(){swap(a[0][0],a[1][0]),swap(a[0][1],a[1][1]),R^=1;}
}t[maxn<<2];
int f[maxn][2],id[maxn],g[maxn];
int Rt,rt;

inline void newnode(int u,int v)
{to[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt;}
inline void getf(int u,int lst)
{
	for(int i=fir[u];i;i=nxt[i])if(to[i]!=lst)
	{
		fa[to[i]]=u,getf(to[i],u);
		if(f[to[i]][0]+1>f[u][0])f[u][1]=f[u][0],f[u][0]=f[to[i]][0]+1,id[u]=to[i];
		else if(f[to[i]][0]+1>f[u][1])f[u][1]=f[to[i]][0]+1;
	}
}
inline void getg(int u,int lst)
{
	for(int i=fir[u];i;i=nxt[i])if(to[i]!=lst)
		g[to[i]]=max(g[u],id[u]==to[i]?f[u][1]:f[u][0])+1,getg(to[i],u);
}

inline void dfs1(int u)
{
	sz[u]=1;
	for(int i=fir[u];i;i=nxt[i])if(to[i]!=fa[u])
	{
		fa[to[i]]=u,dpt[to[i]]=dpt[u]+1;
		dfs1(to[i]),sz[u]+=sz[to[i]];
		if(sz[son[u]]<sz[to[i]])son[u]=to[i];
	}
}
inline void dfs2(int u,int ac)
{
	tp[u]=ac,pos[u]=++cur,Id[cur]=u;
	if(son[u])dfs2(son[u],ac);
	for(int i=fir[u];i;i=nxt[i])if(to[i]!=fa[u]&&to[i]!=son[u])dfs2(to[i],to[i]);
}
inline void pushdown(int i)
{
	if(t[i].C)t[i<<1].revC(),t[i<<1|1].revC(),t[i].C=0;
	if(t[i].R)t[i<<1].revR(),t[i<<1|1].revR(),t[i].R=0;
}
inline void pushup(int i)
{for(int j=0;j<2;j++)for(int k=0;k<2;k++)t[i].a[j][k]=t[i<<1].a[j][k]^t[i<<1|1].a[j][k];}
inline void modify(int i,int l,int r,int p,int x,int y)
{
	if(l==r){t[i].a[0][0]=x,t[i].a[1][0]=y,t[i].a[0][1]=t[i].a[1][1]=0;if(t[i].C)t[i].revC(),t[i].C^=1;return;}
	pushdown(i);
	int mid=(l+r)>>1;
	if(p<=mid)modify(i<<1,l,mid,p,x,y);
	else modify(i<<1|1,mid+1,r,p,x,y);
	pushup(i);
}

inline void updateR(int i,int l,int r,int ql,int qr)
{
	if(qr<l||r<ql)return;
	if(ql<=l&&r<=qr){t[i].revR();return;}
	pushdown(i);int mid=(l+r)>>1;
	updateR(i<<1,l,mid,ql,qr),updateR(i<<1|1,mid+1,r,ql,qr);
	pushup(i);
}
inline void updateC(int i,int l,int r,int ql,int qr)
{
	if(qr<l||r<ql)return;
	if(ql<=l&&r<=qr){t[i].revC();return;}
	pushdown(i);int mid=(l+r)>>1;
	updateC(i<<1,l,mid,ql,qr),updateC(i<<1|1,mid+1,r,ql,qr);
	pushup(i);
}

inline void revR(int u,int p)
{
	while(tp[u]!=tp[p])updateR(1,1,n,pos[tp[u]],pos[u]),u=fa[tp[u]];
	updateR(1,1,n,pos[p],pos[u]);
}
inline void revC(int u,int v)
{
	while(tp[u]!=tp[v])
	{
		if(dpt[tp[u]]<dpt[tp[v]])swap(u,v);
		updateC(1,1,n,pos[tp[u]],pos[u]),u=fa[tp[u]];
	}
	if(dpt[u]>dpt[v])swap(u,v);
	updateC(1,1,n,pos[u],pos[v]);
}

inline int getpos(int u,int p)
{while(tp[u]!=tp[p]){u=tp[u];if(fa[u]==p)return u;u=fa[u];}return son[p];}
inline void transroot(int x)
{
	if(rt!=Rt)revR(rt,getpos(rt,Rt)),modify(1,1,n,pos[Rt],f[Rt][0],f[Rt][1]);
	rt=x;
	if(rt!=Rt)
	{
		int p=getpos(rt,Rt);
		revR(rt,p);
		if(p==id[Rt])modify(1,1,n,pos[Rt],f[Rt][1],f[Rt][0]);
		else modify(1,1,n,pos[Rt],f[Rt][0],f[Rt][1]);
	}
}

int main()
{
	n=getint(),m=getint();
	for(int i=1;i<n;i++)
	{
		int u=getint(),v=getint();
		newnode(u,v),newnode(v,u);
	}
	getf(1,1),getg(1,1);
	for(int i=1;i<=n;i++)
		if(g[i]>f[i][0])f[i][1]=f[i][0],f[i][0]=g[i],id[i]=fa[i];
		else if(g[i]>f[i][1])f[i][1]=g[i];
	for(int i=1;i<=n;i++)
		if(f[i][0]+f[i][1]>f[rt][0]+f[rt][1])rt=i;
		else if(f[i][0]-f[i][1]<f[rt][0]-f[rt][1])rt=i;
	fa[Rt=rt]=0,dfs1(rt),dfs2(rt,rt);
	for(int i=1;i<=n;i++)
		if(i!=Rt)modify(1,1,n,pos[i],f[i][1],f[i][0]);
		else modify(1,1,n,pos[i],f[i][0],f[i][1]);
	transroot(1);
	while(m--)
	{
		int op=getint();
		if(op==1)revC(getint(),getint());
		else
		{
			int x=getint();
			if(x==rt)updateC(1,1,n,1,n);
			else if((pos[x]>=pos[rt]&&pos[x]+sz[x]<=pos[rt]+sz[rt])||pos[x]+sz[x]<=pos[rt]||pos[rt]+sz[rt]<=pos[x])updateC(1,1,n,pos[x],pos[x]+sz[x]-1);
			else
			{
				x=getpos(rt,x);
				updateC(1,1,n,1,pos[x]-1);
				if(pos[x]+sz[x]<=n)updateC(1,1,n,pos[x]+sz[x],n);
			}
		}
		transroot(getint());
		printf("%d\n",t[1].a[0][0]);
	}
}

posted @ 2020-07-18 19:45  Izayoi_Doyo  阅读(194)  评论(0编辑  收藏  举报