zoukankan      html  css  js  c++  java
  • 联考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]);
    	}
    }
    

  • 相关阅读:
    周记
    读书笔记
    我是一只IT小小鸟
    回车键完全替代模拟鼠标单击事件
    去除Flexgrid表格的隔行底色为白的样式
    Flexgrid中的sortable设为false的时候abbr属性也不存在的原因及解决办法
    Flexigrid列之间的拖拉线条在某些浏览器中不能很好地与栏目边缘重合解决方法介绍
    用基于openssl产生的密钥实现PHP和.NET端的RSA加解密互通
    CSS3轮播图
    淘宝放大镜
  • 原文地址:https://www.cnblogs.com/IzayoiDoyo/p/13337048.html
Copyright © 2011-2022 走看看