• 【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;		
    }
    
    
  • 相关阅读:
    Java 入门 36 泛型深入 泛型的概述和优势 自定义泛型类 自定义泛型方法 自定义泛型接口 泛型通配符 上下限
    Java 入门34 常见的数据结构
    Java 入门 40 日志框架 项目阶段 (Java 入门 1924天 需要使用在学)
    Java 入门 31 常用API 日期与时间
    Java 入门 32 包装类 正则表达式 Arrays类 Lambda表达式枚举
    Java 入门35 List系列集合, 几黑的并发修改异常问题 LinkedList
    OpenStack yoga安装(Ubuntu)
    OpenStack命令行添加网卡
    Ceph删除pool
    ceph osd 初始化硬盘时提示OSD::mkfs: ObjectStore::mkfs failed with error (5) Input/output error
  • 原文地址:https://www.cnblogs.com/cjyyb/p/8747978.html
Copyright © 2020-2023  润新知