BZOJ2049: [SDOI2008]Cave 洞穴勘测 LCT

第一道LCT。

动态维护集合就好了。

LCT就是一群链通过父亲关系练成一颗不太连续的树,通过儿子关系组成实边,在这里没有查找单点一说,都是直接拎起来,对于一条链他对外界的有用反馈就是他的链父亲以及需求点的真实位置,而每次cut的时候就会把标记下方好,每次spaly都会找到这个点在这条链中的真实位置,因此这个玄妙的东西就形成了。

null不是一定要用只是简化了你的讨论。

千万别忘了这里的spaly的特别之处!!!!!!!!

#include<cstring>
#include<cstdio>
#define MAXN 10010
using namespace std;
char Cmd[50];
int n,m;
struct Node
{
   Node *f,*ch[2];
   bool rev;
   void pushdown();
}null[MAXN];
inline void swap(Node *&x,Node *&y)
{
   Node *temp=x;
   x=y;
   y=temp;
}
void Node:: pushdown()
{
   if(!rev)return;
   ch[0]->rev^=1;
   ch[1]->rev^=1;
   swap(ch[0],ch[1]);
   rev=0;
}
inline void Init()
{
   scanf("%d%d",&n,&m);
   null->ch[0]=null->ch[1]=null->f=null;
   for(int i=1;i<=n;i++)
    null[i].ch[0]=null[i].ch[1]=null[i].f=null;
}
inline int get(Node *x)
{
   return x->f->ch[1]==x;
}
inline bool isroot(Node *x)
{
   return x->f->ch[1]!=x&&x->f->ch[0]!=x;
}
inline void rotate(Node *x)
{
   Node *fa=x->f,*pa=fa->f;
   int j=get(x);
   if(!isroot(fa))pa->ch[get(fa)]=x;//important point
   if((fa->ch[j]=x->ch[j^1])!=null)fa->ch[j]->f=fa;//important point
   fa->f=x;
   x->f=pa;
   x->ch[j^1]=fa;
}
inline void spaly(Node *x)
{
   x->pushdown();//important point
   for(Node *fa=x->f;!isroot(x);rotate(x),fa=x->f)
    if(!isroot(fa))
    {
     fa->f->pushdown(),fa->pushdown(),x->pushdown();
     rotate(get(x)==get(fa)?fa:x);
    }
    else
     fa->pushdown(),x->pushdown();
}
inline void expose(Node *x)
{
    Node *y=null;
    while(x!=null)
    {
      spaly(x);
      x->ch[1]=y;
      y=x;
      x=x->f;
    }
}
inline void make_root(Node *x)
{
    expose(x);
    spaly(x);
    x->rev^=1;
}
inline Node *get_root(Node *x)
{
    expose(x);
    spaly(x);
    x->pushdown();
    while(x->ch[0]!=null)
      x=x->ch[0],x->pushdown();
    return x;
}
inline void link(Node *x,Node *y)
{
    make_root(x);
    x->f=y;
}
inline void cut(Node *x,Node *y)
{
    make_root(x);
    expose(y);
    spaly(y);
    y->ch[0]->f=null;
    y->ch[0]=null;
}
inline void work()
{
   while(m--)
   {
     int x,y;
     scanf("%s%d%d",Cmd,&x,&y);
     switch(Cmd[0])
     {
        case ‘C‘:link(null+x,null+y);
                 break;
        case ‘D‘:cut(null+x,null+y);
                 break;
        case ‘Q‘:if(get_root(null+x)==get_root(null+y))
                   printf("Yes\n");
                 else
                   printf("No\n");
                 break;
     }
   }
}
int main()
{
   Init();
   work();
   return 0;
}
时间: 2024-10-01 07:21:36

BZOJ2049: [SDOI2008]Cave 洞穴勘测 LCT的相关文章

bzoj2049: [Sdoi2008]Cave 洞穴勘测 lct裸题

题意:三种操作一种摧毁一条边,一种链接一条边,一种查询两个点是否联通 题解:lct的link和cut即可 /************************************************************** Problem: 2049 User: walfy Language: C++ Result: Accepted Time:1896 ms Memory:1508 kb ************************************************

【LCT】BZOJ2049 [SDOI2008]Cave 洞穴勘测

2049: [Sdoi2008]Cave 洞穴勘测 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 10059  Solved: 4863[Submit][Status][Discuss] Description 辉辉热衷于洞穴勘测.某天,他按照地图来到了一片被标记为JSZX的洞穴群地区.经过初步勘测,辉辉发现这片区域由n个洞穴(分别编号为1到n)以及若干通道组成,并且每条通道连接了恰好两个洞穴.假如两个洞穴可以通过一条或者多条通道按一定顺序连接起

BZOJ 2049([Sdoi2008]Cave 洞穴勘测-LCT)[Template:LCT]

2049: [Sdoi2008]Cave 洞穴勘测 Time Limit: 10 Sec  Memory Limit: 259 MB Submit: 4809  Solved: 2141 [Submit][Status][Discuss] Description 辉辉热衷于洞穴勘测.某天,他按照地图来到了一片被标记为JSZX的洞穴群地区.经过初步勘测,辉辉发现这片区域由n个洞穴(分别编号为1到n)以及若干通道组成,并且每条通道连接了恰好两个洞穴.假如两个洞穴可以通过一条或者多条通道按一定顺序连接

[bzoj2049][Sdoi2008]Cave 洞穴勘测_LCT

Cave 洞穴勘测 bzoj-2049 Sdoi-2008 题目大意:维护一个数据结构,支持森林中加边,删边,求两点连通性.n个点,m个操作. 注释:$1\le n\le 10^4$,$1\le m\le 2\cdot 10^5$. 想法:刚学了一发LCT,写一道照学长抄一道板子题.话说什么是LCT? 就是一个贼nb的数据结构,支持加边删边后的什么路径和子树信息啥的,这就是LCT. 艾欧欸软可以的blog 这道题,我们只需要其中的link,cut和find即可. 最后,附上代码.. ... #i

[BZOJ2049] [CodeVS1839] [SDOI2008] Cave 洞穴勘测 (LCT)

Description 辉辉热衷于洞穴勘测.某天,他按照地图来到了一片被标记为JSZX的洞穴群地区.经过初步勘测,辉辉发现这片区域由n个洞穴(分别编号为1到n)以及若干通道组成,并且每条通道连接了恰好两个洞穴.假如两个洞穴可以通过一条或者多条通道按一定顺序连接起来,那么这两个洞穴就是连通的,按顺序连接在一起的这些通道则被称之为这两个洞穴之间的一条路径.洞穴都十分坚固无法破坏,然而通道不太稳定,时常因为外界影响而发生改变,比如,根据有关仪器的监测结果,123号洞穴和127号洞穴之间有时会出现一条通

BZOJ 2049 [Sdoi2008]Cave 洞穴勘测 LCT

题意:链接 方法: LCT 解析: 搞了一下午的LCT,这道题就当做第一道模板?题.然后大概写个理解总结什么的. 首先!splay不要写挂!不要写挂! 然后对于这道题.没有什么奇怪的操作. 只有两个操作,将两个节点连起来,将两个节点之间的连边断开. 每一次询问,询问两个节点是否连通. 听起来挺简单的,一下子就想到了并查集有没有! 然而发现并查集并不可以搞. 也许是我太弱,但是我真的不会并查集的分割. 所以还是老老实实来想LCT. LCT 顾名思义,Link Cut 是其比较有代表性的操作? 首先

bzoj2049: [Sdoi2008]Cave 洞穴勘测

[题意] 给你一个森林,要求支持动态加边删边,并会询问在某一个时刻两点是否联通. [题解] 裸的lct,模版题.第一次写对lct,没写过真的难写.... [代码] 1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 using namespace std; 5 const int N=10005; 6 int n,Q,x,y; 7 int c[N][2],fa[N],rev[N],a[N]

bzoj2049 [Sdoi2008]Cave 洞穴勘测 link cut tree入门

link cut tree入门题 首先说明本人只会写自底向上的数组版(都说了不写指针.不写自顶向下QAQ……) 突然发现link cut tree不难写... 说一下各个函数作用: bool isroot(int x):判断x是否为所在重链(splay)的根 void down(int x):下放各种标记 void rotate(int x):在x所在重链(splay)中将x旋转到fa[x]的位置上 void splay(int x):在x坐在重链(splay)中将x旋转到根 void acce

BZOJ 2049: [Sdoi2008]Cave 洞穴勘测

二次联通门 : BZOJ 2049: [Sdoi2008]Cave 洞穴勘测 其实指针也不是很慢 我的指针代码能吊打70%的数组 及80%的指针.... /* BZOJ 2049: [Sdoi2008]Cave 洞穴勘测 LCT 连边 删边 查询是否在同一树中时, 只需要一直向上跳 看看树根是否相同就好了 */ #include <cstdio> #include <cstdlib> #include <iostream> #define Max 400009 int