zoukankan      html  css  js  c++  java
  • 【SPOJ】QTREE6(Link-Cut-Tree)

    【SPOJ】QTREE6(Link-Cut-Tree)

    题面

    Vjudge

    题解

    很神奇的一道题目
    我们发现点有黑白两种,又是动态加边/删边
    不难想到(LCT)

    最爆力的做法,显然是每次修改单点颜色的时候
    暴力修改当前点和它的父亲以及儿子之间的连边状态

    但是这样显然是假的(菊花树了解一下)

    怎么优化呢?
    对于每次操作,我们考虑如何只修改一次。
    对于树上的一个结点,如果只修改一次,显然是修改和其父亲的状态。
    那么,我们在考虑(LCT)的连边操作的时候,
    如果当前点变色,那么就只修改和它父亲的连边。
    这样怎么算答案呢?
    如果我们确定树是一棵有根树
    那么,我们只需要找到当前点深度最浅的父亲
    这个父亲在当前颜色的树上的儿子个数显然就是答案

    所以,我们只需要每次只修改当前点和其父亲的关系就行了。
    但是要注意一个问题,因为强制是有根树了。
    所以打死都不能有(makeroot)操作
    所以(link,cut)之类的都要魔改一发了。。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define ll long long
    #define RG register
    #define MAX 111111
    #define ls (t[x].ch[0])
    #define rs (t[x].ch[1])
    inline int read()
    {
        RG int x=0,t=1;RG char ch=getchar();
        while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
        if(ch=='-')t=-1,ch=getchar();
        while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
        return x*t;
    }
    struct Line{int v,next;}e[MAX<<1];
    int h[MAX],cnt=1;
    inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
    struct Link_Cut_Tree
    {
    	struct Node
    	{
    		int ch[2],ff;
    		int size,sum;
    		int rev;
    	}t[MAX];
    	bool isroot(int x){return t[t[x].ff].ch[0]!=x&&t[t[x].ff].ch[1]!=x;}
    	void pushup(int x){t[x].sum=t[ls].sum+t[rs].sum+t[x].size+1;}
    	void rotate(int x)
    	{
    		int y=t[x].ff,z=t[y].ff;
    		int k=t[y].ch[1]==x;
    		if(!isroot(y))t[z].ch[t[z].ch[1]==y]=x;t[x].ff=z;
    		t[y].ch[k]=t[x].ch[k^1];t[t[x].ch[k^1]].ff=y;
    		t[x].ch[k^1]=y;t[y].ff=x;
    		pushup(y);pushup(x);
    	}
    	void Splay(int x)
    	{
    		while(!isroot(x))
    		{
    			int y=t[x].ff,z=t[y].ff;
    			if(!isroot(y))
    				(t[y].ch[0]==x)^(t[z].ch[0]==y)?rotate(x):rotate(y);
    			rotate(x);
    		}
    		pushup(x);
    	}
    	void access(int x)
    	{
    		for(int y=0;x;y=x,x=t[x].ff)
    		{
    			Splay(x);t[x].size+=t[rs].sum-t[y].sum;
    			rs=y;pushup(x);
    		}
    	}
    	void link(int x,int y){if(!y)return;access(y);Splay(x);Splay(y);t[x].ff=y;t[y].size+=t[x].sum;pushup(y);}
    	void cut(int x,int y){if(!y)return;access(x);Splay(x);ls=t[ls].ff=0;pushup(x);}
    	int findroot(int x){access(x);Splay(x);while(ls)x=ls;Splay(x);return x;}
    }LCT[2];
    int n,m,fa[MAX],c[MAX];
    void dfs(int u,int ff)
    {
    	for(int i=h[u];i;i=e[i].next)
    	{
    		int v=e[i].v;if(v==ff)continue;
    		LCT[1].link(v,u);fa[v]=u;
    		dfs(v,u);
    	}
    }
    int main()
    {
    	n=read();
    	for(int i=1;i<=n;++i)c[i]=1;
    	for(int i=1,u,v;i<n;++i)u=read(),v=read(),Add(u,v),Add(v,u);
    	dfs(1,0);
    	m=read();
    	while(m--)
    	{
    		int opt=read(),x=read();
    		if(opt)LCT[c[x]].cut(x,fa[x]),c[x]^=1,LCT[c[x]].link(x,fa[x]);
    		else
    		{
    			LCT[c[x]].access(x);
    			int ff=LCT[c[x]].findroot(x);
    			if(c[ff]==c[x])printf("%d
    ",LCT[c[x]].t[ff].sum);
    			else printf("%d
    ",LCT[c[x]].t[LCT[c[x]].t[ff].ch[1]].sum);
    		}
    	}
    	return 0;		
    }
    
    
  • 相关阅读:
    解决EXC_BAD_ACCESS错误的一种方法--NSZombieEnabled
    关于deselectRowAtIndexPath
    CGRectInset、CGRectOffset、等对比整理
    代码设置UITableViewCell 各个组件间距
    UITableViewCell计算行高
    设置UITableView中UIImage的大小
    UILbale自动换行
    根据字体多少使UILabel自动调节尺寸
    ios通过url下载显示图片
    Python【requests】第三方模块
  • 原文地址:https://www.cnblogs.com/cjyyb/p/8747978.html
Copyright © 2011-2022 走看看