【SDOI2008】洞穴勘测 - LCT

题目描述

辉辉热衷于洞穴勘测。

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

辉辉有一台监测仪器可以实时将通道的每一次改变状况在辉辉手边的终端机上显示:

如果监测到洞穴u和洞穴v之间出现了一条通道,终端机上会显示一条指令 Connect u v

如果监测到洞穴u和洞穴v之间的通道被毁,终端机上会显示一条指令 Destroy u v

经过长期的艰苦卓绝的手工推算,辉辉发现一个奇怪的现象:无论通道怎么改变,任意时刻任意两个洞穴之间至多只有一条路径。

因而,辉辉坚信这是由于某种本质规律的支配导致的。因而,辉辉更加夜以继日地坚守在终端机之前,试图通过通道的改变情况来研究这条本质规律。 然而,终于有一天,辉辉在堆积成山的演算纸中崩溃了……他把终端机往地面一砸(终端机也足够坚固无法破坏),转而求助于你,说道:“你老兄把这程序写写吧”。

辉辉希望能随时通过终端机发出指令 Query u v,向监测仪询问此时洞穴u和洞穴v是否连通。现在你要为他编写程序回答每一次询问。 已知在第一条指令显示之前,JSZX洞穴群中没有任何通道存在。

输入输出格式

输入格式: 

第一行为两个正整数n和m,分别表示洞穴的个数和终端机上出现过的指令的个数。 以下m行,依次表示终端机上出现的各条指令。每行开头是一个表示指令种类的字符串s("Connect”、”Destroy”或者”Query”,区分大小写),之后有两个整数u和v (1≤u, v≤n且u≠v) 分别表示两个洞穴的编号。

输出格式:

对每个Query指令,输出洞穴u和洞穴v是否互相连通:是输出”Yes”,否则输出”No”。(不含双引号)

思路

LCT板子,网上有很多介绍的

#include <bits/stdc++.h>
using namespace std;
const int maxn = 10000 + 10;
struct Link_Cut_Tree {
    struct Splay { int ch[2],f,mark,sum,w; }t[maxn];
    inline bool getfa(int x) { return t[t[x].f].ch[1] == x; }
    inline bool isroot(int x) { return t[t[x].f].ch[0] != x && t[t[x].f].ch[1] != x; }
    inline void pushup(int x) { t[x].sum = t[t[x].ch[0]].sum^t[t[x].ch[1]].sum^t[x].w; }
    inline void rev(int x) { t[x].mark ^= 1; swap(t[x].ch[0],t[x].ch[1]); }
    inline void pushdown(int x) {
        if (t[x].mark) {
            if (t[x].ch[0]) rev(t[x].ch[0]);
            if (t[x].ch[1]) rev(t[x].ch[1]);
            t[x].mark = 0;
        }
    }
    inline void rotate(int x) {
        int f = t[x].f,g = t[f].f,c = getfa(x);
        if (!isroot(f)) t[g].ch[getfa(f)]=x; t[x].f = g;
        t[f].ch[c] = t[x].ch[c^1]; t[t[f].ch[c]].f = f;
        t[x].ch[c^1] = f; t[f].f = x;
        pushup(f); pushup(x);
    }
    inline void check(int x) { if (!isroot(x)) check(t[x].f); pushdown(x); }
    inline void splay(int x) {
        check(x);
        for (;!isroot(x);rotate(x))
            if (!isroot(t[x].f)) rotate(getfa(t[x].f) == getfa(x) ? t[x].f : x);
    }
    inline void access(int x) { for (int y = 0;x;y = x,x = t[x].f) splay(x),t[x].ch[1] = y,pushup(x); }
    inline void makeroot(int x) { access(x); splay(x); rev(x); }
    inline int findroot(int x) {
        access(x); splay(x);
        while (t[x].ch[0]) pushdown(x),x = t[x].ch[0];
        return x;
    }
    inline void link(int x,int y) { makeroot(x),t[x].f = y; }
    inline void cut(int x,int y) { makeroot(x); access(y); splay(y); if (t[y].ch[0] == x && t[x].ch[1] == 0) t[x].f = t[y].ch[0] = 0; }
    inline void split(int x,int y) { makeroot(x); access(y); splay(y); }
}lct;
int n,q;
int main() {
    scanf("%d%d",&n,&q);
    while (q--) {
        string op;
        int x,y;
        cin >> op >> x >> y;
        if (op == "Connect") lct.link(x,y);
        if (op == "Destroy") lct.cut(x,y);
        if (op == "Query") printf("%s\n",lct.findroot(x) == lct.findroot(y) ? "Yes" : "No");
    }
    return 0;
}

---恢复内容结束---

原文地址:https://www.cnblogs.com/lrj124/p/8973793.html

时间: 2024-10-11 16:25:28

【SDOI2008】洞穴勘测 - LCT的相关文章

BZOJ2049 SDOI2008 洞穴勘测 LCT

题意:给定一棵树,维护:1.删除一条边  2.添加一条边  3.询问u和v是否连通 题解:LCT维护连通性 #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; const int MAXN=10000+2; typedef struct NODE{ NODE *ch

[LuoguP2147] [SDOI2008]洞穴勘测 (LCT维护连通性)

题面 传送门:https://www.luogu.org/problemnew/show/P2147 Solution 这题...... 我们可以发现题目要求我们维护一个动态森林,而且只查询连通性.... 显然LCT模板题啊,关于LCT玩法,可以猛戳这里学习 Code #include<iostream> #include<cstdio> #include<vector> using namespace std; long long read() { long long

P2147 [SDOI2008]洞穴勘测

题目 P2147 [SDOI2008]洞穴勘测 做法 说实话如果你在看这篇题解的话应该也没有人劝你回去打模板吧 My complete code #include<cstdio> #include<cstring> #include<iostream> #include<string> using namespace std; typedef int LL; const LL maxn=1e6; inline LL Read(){ LL x(0),f(1);

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

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

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]洞穴勘测——题解

http://www.lydsy.com/JudgeOnline/problem.php?id=2049 https://www.luogu.org/problemnew/show/P2147 辉辉热衷于洞穴勘测. 某天,他按照地图来到了一片被标记为JSZX的洞穴群地区.经过初步勘测,辉辉发现这片区域由n个洞穴(分别编号为1到n)以及若干通道组成,并且每条通道连接了恰好两个洞穴.假如两个洞穴可以通过一条或者多条通道按一定顺序连接起来,那么这两个洞穴就是连通的,按顺序连接在一起的这些通道则被称之为

BZOJ 2049 [Sdoi2008]Cave 洞穴勘测 LCT

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

BZOJ2049: [SDOI2008]Cave 洞穴勘测 LCT

第一道LCT. 动态维护集合就好了. LCT就是一群链通过父亲关系练成一颗不太连续的树,通过儿子关系组成实边,在这里没有查找单点一说,都是直接拎起来,对于一条链他对外界的有用反馈就是他的链父亲以及需求点的真实位置,而每次cut的时候就会把标记下方好,每次spaly都会找到这个点在这条链中的真实位置,因此这个玄妙的东西就形成了. null不是一定要用只是简化了你的讨论. 千万别忘了这里的spaly的特别之处!!!!!!!! #include<cstring> #include<cstdio

【BZOJ2049】【SDOI2008】Cave 洞穴勘测 LCT裸题 模版题 数组版

数组,至少目前我只写数组,不写指针. LCT这种东西我不打算讲或者什么乱七八糟的,反正这一篇是自用. 同样,看这篇博客的人可以先去别的地方学LCT,然后来我这扒代码. 代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define ls son[x][0] #define rs son[x][1] #define is(x) (x==son[f