• 7.18 NOI模拟赛 树论 线段树 树链剖分 树的直径的中心 SG函数 换根


    LINK:树论

    avatar
    avatar
    avatar

    不愧是我认识的出题人 出的题就是牛掰 == 他好像不认识我

    考试的时候 只会写42 还有两个subtask写挂了 拿了37 确实两个subtask合起来只有5分的好成绩

    父亲能转移到自己的子树内部的一点所以要从叶子结点往根考虑.

    一个棋子的时候 单独某个点的SG函数不难推 这个点可以放到儿子任意一点 而儿子的SG函数值已知就很容易推出来了.

    当然叶子结点的SG函数值为0.

    显然整棵树的SG函数为异或和 可以看成若干个不交的游戏的组合.

    考虑某个点两个棋子的时候的SG函数 经过不断的推导/猜想可以发现为0因为这两个棋子互不干扰 也可以看成是两个游戏的组合 所以可以直接异或起来.

    进一步的可以推得 某个点的SG函数 如果为偶数那么为0 如果为奇数就是自己子树内部离自己最远的儿子的距离.

    这样就可以写出一个(ncdot m)的暴力了。

    考虑每次根都为1的情况 显然每次只有子树内部加 链加的操作。

    直接树链剖分 翻转一下标记即可.

    考虑只存在操作1 且每次为单点修改操作.

    经过观察可以发现某个点SG函数只有两种 利用线段树维护dfs序的以每个点为根的值.

    容易在线段树上完成修改 要么是连续的一段 要么是两头.

    这样每次单点修改就再次异或一下即可.

    考虑只存在操作1的情况.

    比上个情况其实多了一个链加 和 子树的修改.

    都不太好做其实.

    考虑正解。考虑直径的中点.

    每个点的两种值 在以直径中点为根的时候变化比较规律.

    如 当直径中点的时候 每个点都为自己子树内部的最大深度.

    换根的时候 其实是 只有根到换到的那个点路径上的点会变化

    这样就解决了换根的问题 在线段树上直接交换即可。

    考虑链加 也可以直接做了.

    子树加 考虑和当前根的关系 如果是子树外面那部分的可以考虑求出x到根的第一个点翻转再整体翻转即可。

    线段树内部的话要维护四个值。

    每次行翻转或者列翻转打上标记即可.

    code
    //#include<bits/stdc++.h>
    #include<iostream>
    #include<cstdio>
    #include<ctime>
    #include<cctype>
    #include<queue>
    #include<deque>
    #include<stack>
    #include<iostream>
    #include<iomanip>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<ctime>
    #include<cmath>
    #include<cctype>
    #include<cstdlib>
    #include<queue>
    #include<deque>
    #include<stack>
    #include<vector>
    #include<algorithm>
    #include<utility>
    #include<bitset>
    #include<set>
    #include<map>
    #define ll long long
    #define db double
    #define INF 1000000000
    #define ldb long double
    #define pb push_back
    #define put_(x) printf("%d ",x);
    #define get(x) x=read()
    #define gt(x) scanf("%d",&x)
    #define gi(x) scanf("%lf",&x)
    #define put(x) printf("%d
    ",x)
    #define putl(x) printf("%lld
    ",x)
    #define rep(p,n,i) for(RE int i=p;i<=n;++i)
    #define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
    #define fep(n,p,i) for(RE int i=n;i>=p;--i)
    #define vep(p,n,i) for(RE int i=p;i<n;++i)
    #define pii pair<int,int>
    #define mk make_pair
    #define RE register
    #define P 1000000007ll
    #define gf(x) scanf("%lf",&x)
    #define pf(x) ((x)*(x))
    #define uint unsigned long long
    #define ui unsigned
    #define EPS 1e-4
    #define sq sqrt
    #define S second
    #define F first
    #define mod 1000000007
    #define l(x) t[x].l
    #define r(x) t[x].r
    #define tag0(p) t[p].tag0
    #define tag1(p) t[p].tag1
    #define zz p<<1
    #define yy p<<1|1
    using namespace std;
    char *fs,*ft,buf[1<<15];
    inline char gc()
    {
    	return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline int read()
    {
    	RE int x=0,f=1;RE char ch=gc();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
    	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=gc();}
    	return x*f;
    
    }
    const int MAXN=200010;
    int n,m,len,Q,cnt,top1,mx,target,rt,maxx,flag,s1,s2;
    int fa[MAXN],top[MAXN],f[MAXN],idf[MAXN],g[MAXN],idg[MAXN];
    int pos[MAXN],dfn[MAXN],las[MAXN],s[MAXN],d[MAXN],sz[MAXN],son[MAXN];
    int lin[MAXN],ver[MAXN<<1],nex[MAXN<<1];
    struct wy{int a[2][2];int l,r,tag0,tag1;}t[MAXN<<2];
    inline void add(int x,int y)
    {
    	ver[++len]=y;nex[len]=lin[x];lin[x]=len;
    	ver[++len]=x;nex[len]=lin[y];lin[y]=len;
    }
    inline void dfs(int x,int fa)
    {
    	if(d[x]>mx)target=x,mx=d[x];
    	go(x)if(tn!=fa)
    	{
    		d[tn]=d[x]+1;
    		dfs(tn,x);
    	}
    }
    inline void find(int x,int fa)
    {
    	s[++top1]=x;
    	if(x==s2){flag=1;return;}
    	go(x)if(tn!=fa)
    	{
    		find(tn,x);
    		if(flag)return;
    	}
    	--top1;
    }
    inline void find_rt()
    {
    	mx=0;dfs(1,0);s1=target;
    	mx=0;dfs(s1,0);s2=target;
    	find(s1,0);rt=s[(1+top1)>>1];
    }
    inline void dfs1(int x,int father)
    {
    	fa[x]=father;d[x]=d[father]+1;sz[x]=1;
    	go(x)if(tn!=father)
    	{
    		dfs1(tn,x);
    		sz[x]+=sz[tn];
    		if(sz[son[x]]<sz[tn])son[x]=tn;
    		if(g[x]<f[tn]+1)g[x]=f[tn]+1,idg[x]=tn;
    		if(f[x]<g[x])swap(g[x],f[x]),swap(idg[x],idf[x]);
    	}
    }
    inline void dp(int x,int father)
    {
    	if(x!=rt)
    	{
    		int ww=idf[fa[x]]==x?g[fa[x]]:f[fa[x]];
    		if(g[x]<ww+1)g[x]=ww+1,idg[x]=fa[x];
    		if(f[x]<g[x])swap(g[x],f[x]),swap(idg[x],idf[x]);
    	}
    	dfn[x]=++cnt;pos[cnt]=x;top[x]=father;
    	if(son[x])dp(son[x],father);
    	go(x)if(tn!=son[x]&&tn!=fa[x])dp(tn,tn);
    	las[x]=cnt;
    }
    inline void pushup(int p)
    {
    	t[p].a[0][0]=t[zz].a[0][0]^t[yy].a[0][0];
    	t[p].a[0][1]=t[zz].a[0][1]^t[yy].a[0][1];
    	t[p].a[1][0]=t[zz].a[1][0]^t[yy].a[1][0];
    	t[p].a[1][1]=t[zz].a[1][1]^t[yy].a[1][1];
    }
    inline void build(int p,int l,int r)
    {
    	l(p)=l;r(p)=r;
    	if(l==r)
    	{
    		t[p].a[0][0]=g[pos[l]];
    		t[p].a[0][1]=f[pos[l]];
    		return;
    	}
    	int mid=(l+r)>>1;
    	build(zz,l,mid);
    	build(yy,mid+1,r);
    	pushup(p);
    }
    inline void bj0(int x)
    {
    	swap(t[x].a[0][0],t[x].a[0][1]);
    	swap(t[x].a[1][0],t[x].a[1][1]);
    	tag0(x)^=1;
    }
    inline void bj1(int x)
    {
    	swap(t[x].a[0][0],t[x].a[1][0]);
    	swap(t[x].a[0][1],t[x].a[1][1]);
    	tag1(x)^=1;
    }
    inline void pushdown(int p)
    {
    	if(tag0(p))bj0(zz),bj0(yy),tag0(p)=0;
    	if(tag1(p))bj1(zz),bj1(yy),tag1(p)=0;
    }
    inline int find_son(int x,int y)
    {
    	while(top[x]!=top[y])
    	{
    		y=top[y];
    		if(fa[y]==x)break;
    		y=fa[y];
    	}
    	return fa[y]==x?y:son[x];
    }
    inline void change0(int p,int l,int r)
    {
    	if(l<=l(p)&&r>=r(p))return bj0(p);
    	int mid=(l(p)+r(p))>>1;
    	if(tag0(p)||tag1(p))pushdown(p);
    	if(l<=mid)change0(zz,l,r);
    	if(r>mid)change0(yy,l,r);
    	pushup(p);
    }
    inline void modify(int x,int y)
    {
    	if(x!=y)
    	{
    		int ww=find_son(x,y);
    		if(ww==idf[x])change0(1,1,1);
    	}
    	while(top[x]!=top[y])
    	{
    		change0(1,dfn[top[y]],dfn[y]);
    		y=fa[top[y]];
    	}
    	change0(1,dfn[x],dfn[y]);
    }
    inline void change1(int p,int l,int r)
    {
    	if(l<=l(p)&&r>=r(p))return bj1(p);
    	int mid=(l(p)+r(p))>>1;
    	if(tag0(p)||tag1(p))pushdown(p);
    	if(l<=mid)change1(zz,l,r);
    	if(r>mid)change1(yy,l,r);
    	pushup(p);
    }
    inline void Tchange(int x,int y)
    {
    	int fx=top[x],fy=top[y];
    	while(fx!=fy)
    	{
    		if(d[fx]<d[fy])swap(x,y),swap(fx,fy);
    		change1(1,dfn[fx],dfn[x]);
    		x=fa[fx];fx=top[x];
    	}
    	if(d[x]<d[y])swap(x,y);
    	change1(1,dfn[y],dfn[x]);
    }
    int main()
    {
    	freopen("tree.in","r",stdin);
    	freopen("tree.out","w",stdout);
    	get(n);get(m);
    	if(n==1)
    	{
    		rep(1,m,i)puts("0");
    		return 0;
    	}
    	rep(2,n,i)add(read(),read());
    	find_rt();
    	dfs1(rt,0);dp(rt,rt);
    	build(1,1,n);int now=1;
    	//put(t[1].a[0][0]);
    	modify(rt,now);
    	//put(t[1].a[0][0]);
    	rep(1,m,i)
    	{
    		int get(op);
    		if(op==1)Tchange(read(),read());
    		else
    		{
    			int get(x);
    			if(x==now)change1(1,1,n);
    			else 
    			{
    				if(dfn[now]<dfn[x]||las[x]<dfn[now])
    					change1(1,dfn[x],las[x]);
    				else
    				{
    					x=find_son(x,now);
    					change1(1,1,n);
    					change1(1,dfn[x],las[x]);
    				}
    			}
    		}
    		modify(rt,now);
    		now=read();
    		modify(rt,now);
    		put(t[1].a[0][0]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    dubbo监控报错Error creating bean with name 'uriBrokerService'
    Mysql批量导入约束报错
    Spring+Mybatis+Dubbo报错java.lang.reflect.MalformedParameterizedTypeException
    group by查询每组时间最新的一条记录
    Ztree
    朴素贝叶斯算法原理小结
    SimRank协同过滤推荐算法
    用Spark学习矩阵分解推荐算法
    XGBoost算法原理小结
    集成学习之Adaboost算法原理小结
  • 原文地址:https://www.cnblogs.com/chdy/p/13337992.html
Copyright © 2020-2023  润新知