BZOJ 2049 洞穴勘测 Link-Cut-Tree(LCT)

警告 本篇文章作者已神志不清 文章内可能出现 病句 逻辑不通 粗口 爆鲤 瑟琴 低幼 第三类接触 外语 等特征 请阅读时注意过滤和脑补

妈蛋从下午五点开始写写到快九点才AC。。。。啊啊啊啊啊啊啊 啊啊啊啊啊啊啊 啊啊啊啊 啊啊啊啊啊啊啊 啊啊啊啊啊 啊啊啊啊 啊啊

题目大意:给定一堆点,提供三种操作:

1.给定x和y,询问x和y是否在一棵子树上

2.在x和y之间连一条边 数据保证x和y不连通

3.删除x和y之间的边 数据保证x和y之间有连边

乍一看这好像是并查集?但是并查集不支持拆分操作

仔细一看数据是森林 于是这题LCT

本来以为把2002的代码改改就能过 结果 NMB NMB NMB 啊啊啊啊啊啊啊啊 22323232323233333333333333333

该拆的边拆不掉 连边成了环 無限TLE

问题就在于这题是无根树

无根树Link的时候不能直接把节点和爸爸拆了 而是要把节点变成整棵树的根 然后再合并

而变为根节点的方式就是先Access+Splay 然后将x所在Splay子树反转 Splay在维护的时候要向上找到标记向下下传

Cut的时候先把x Access+Splay+反转 然后把x和右节点切断 把y Access 再切断一遍 把y Splay 这样一定保证y->fa==x && x->rs!=y

贴代码 下午没吃饭 饿死我了0.0

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 10100
using namespace std;
int n,m;
struct abcd{
    abcd *ls,*rs,*fa;
    bool mark;
    abcd();
};
abcd *null=new abcd,tree[M];
abcd :: abcd()
{
    ls=rs=fa=null;
}
void Zig(abcd*x)
{
    abcd*y=x->fa;
    abcd*z=y->fa;
    y->ls=x->rs;
    x->rs->fa=y;
    x->rs=y;
    y->fa=x;
    if (z->ls==y)
        z->ls=x;
    else if(z->rs==y)
        z->rs=x;
    x->fa=z;
}
void Zag(abcd*x)
{
    abcd*y=x->fa;
    abcd*z=y->fa;
    y->rs=x->ls;
    x->ls->fa=y;
    x->ls=y;
    y->fa=x;
    if (z->ls==y)
        z->ls=x;
    else if(z->rs==y)
        z->rs=x;
    x->fa=z;
}
void Reverse(abcd *x)
{
	if(x==x->fa->ls||x==x->fa->rs)
		Reverse(x->fa);
	if(x->mark)
	{
		swap(x->ls,x->rs);
		x->mark=0;
		x->ls->mark^=1;
		x->rs->mark^=1;
	}
}
void Splay(abcd*x)
{
    abcd *y,*z;
    Reverse(x);
    for (;x->fa->ls==x||x->fa->rs==x;)
    {
        y=x->fa,z=y->fa;
        if (y->ls==x)
        {
            if (z->ls==y)
                Zig(y);
            Zig(x);
        }
        else
        {
            if (z->rs==y)
                Zag(y);
            Zag(x);
        }
    }
}
void Access(abcd *x)
{
    abcd *y=null;
    while(x!=null)
    {
        Splay(x);
        x->rs=y;
        y=x;
        x=x->fa;
    }
}
void Query(abcd *x,abcd *y)
{
    Access(x);
    Splay(x);
    while(y->fa!=null)
        y=y->fa;
    if(y==x)
        puts("Yes");
    else
        puts("No");
}
void Link(abcd *x,abcd *y)
{
    Access(x);
    Splay(x);
    x->mark^=1;
    Reverse(x);
    x->ls=null;
    x->fa=y;
}
void Cut(abcd *x,abcd *y)
{
	Access(x);
    Splay(x);
    x->mark^=1;
    Reverse(x);
    x->rs=null;
    Access(y);
    x->rs=null;
    Splay(y);
    y->fa=null;
}
int main()
{
    null->ls=null->rs=null->fa=null;
    int i,x,y;
    char p[100];
    cin>>n>>m;
    for (i=1;i<=m;i++)
    {
        scanf("%s%d%d",p,&x,&y);
        if(p[0]=='Q')
            Query(&tree[x],&tree[y]);
        else if(p[0]=='C')
            Link(&tree[x],&tree[y]);
        else
            Cut(&tree[x],&tree[y]);
    }
}


你可能感兴趣的:(动态树,bzoj,LCT,Link-Cut-Tree,BZOJ2049)