1. 程式人生 > >bzoj 2049 洞穴勘測 lct

bzoj 2049 洞穴勘測 lct

2049: [Sdoi2008]Cave 洞穴勘測

Time Limit: 10 Sec  Memory Limit: 259 MB
Submit: 11475  Solved: 5683
[Submit][Status][Discuss]

Description

輝輝熱衷於洞穴勘測。某天,他按照地圖來到了一片被標記為JSZX的洞穴群地區。經過初步勘測,輝輝發現這片區域由n個洞穴(分別編號為1到n)以及若干通道組成,並且每條通道連線了恰好兩個洞穴。假如兩個洞穴可以通過一條或者多條通道按一定順序連線起來,那麼這兩個洞穴就是連通的,按順序連線在一起的這些通道則被稱之為這兩個洞穴之間的一條路徑。洞穴都十分堅固無法破壞,然而通道不太穩定,時常因為外界影響而發生改變,比如,根據有關儀器的監測結果,123號洞穴和127號洞穴之間有時會出現一條通道,有時這條通道又會因為某種稀奇古怪的原因被毀。輝輝有一臺監測儀器可以實時將通道的每一次改變狀況在輝輝手邊的終端機上顯示:如果監測到洞穴u和洞穴v之間出現了一條通道,終端機上會顯示一條指令 Connect u v 如果監測到洞穴u和洞穴v之間的通道被毀,終端機上會顯示一條指令 Destroy u v 經過長期的艱苦卓絕的手工推算,輝輝發現一個奇怪的現象:無論通道怎麼改變,任意時刻任意兩個洞穴之間至多隻有一條路徑。因而,輝輝堅信這是由於某種本質規律的支配導致的。因而,輝輝更加夜以繼日地堅守在終端機之前,試圖通過通道的改變情況來研究這條本質規律。然而,終於有一天,輝輝在堆積成山的演算紙中崩潰了……他把終端機往地面一砸(終端機也足夠堅固無法破壞),轉而求助於你,說道:“你老兄把這程式寫寫吧”。輝輝希望能隨時通過終端機發出指令 Query u v,向監測儀詢問此時洞穴u和洞穴v是否連通。現在你要為他編寫程式回答每一次詢問。已知在第一條指令顯示之前,JSZX洞穴群中沒有任何通道存在。

Input

第一行為兩個正整數n和m,分別表示洞穴的個數和終端機上出現過的指令的個數。以下m行,依次表示終端機上出現的各條指令。每行開頭是一個表示指令種類的字串s("Connect”、”Destroy”或者”Query”,區分大小寫),之後有兩個整數u和v (1≤u, v≤n且u≠v) 分別表示兩個洞穴的編號。

Output

對每個Query指令,輸出洞穴u和洞穴v是否互相連通:是輸出”Yes”,否則輸出”No”。(不含雙引號)

Sample Input

樣例輸入1 cave.in
200 5
Query 123 127
Connect 123 127
Query 123 127
Destroy 127 123
Query 123 127
樣例輸入2 cave.in

3 5
Connect 1 2
Connect 3 1
Query 2 3
Destroy 1 3
Query 2 3


 

Sample Output

樣例輸出1 cave.out
No
Yes
No


樣例輸出2 cave.out

Yes
No

lct維護動態集合

#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
 
#define ll long long
#define lson tr[x][0]
#define rson tr[x][1]
const int maxn = 1e4 + 10;
const int INF = 1e9;
int top;
int  fa[maxn], tr[maxn][2];
int tag[maxn], ve[maxn];
char op[10];
 
int judge(int x) {
    return tr[fa[x]][1] == x;
}
 
int isroot(int x) {
    return (tr[fa[x]][0] != x && tr[fa[x]][1] != x);
}
 
void pushdown(int x) {
    if (tag[x]) {
        tag[lson] ^= 1;
        tag[rson] ^= 1;
        swap(lson, rson);
        tag[x] = 0;
    }
}
 
void rotate(int x) {
    int y = fa[x], d = judge(x);
    if (tr[y][d] = tr[x][d ^ 1]) fa[tr[y][d]] = y;
    if ((fa[x] = fa[y]) && !isroot(y)) tr[fa[y]][judge(y)] = x;
    tr[fa[y] = x][d ^ 1] = y;
}
 
void splay(int x) {
    for (int y = ve[top = 1] = x; !isroot(y); y = fa[y])
        ve[++top] = fa[y];
    while (top) pushdown(ve[top--]);
    for (int y; !isroot(x); rotate(x))
        if (!isroot(y = fa[x])) rotate(judge(x) == judge(y) ? y : x);
}
 
void access(int x) {
    for (int y = 0; x; x = fa[y = x]) {
        splay(x);
        tr[x][1] = y;
    }
}
 
void makeroot(int x) {
    access(x);
    splay(x);
    tag[x] ^= 1;
}
 
int findroot(int x) {
    access(x);
    splay(x);
    pushdown(x);
    while (lson) pushdown(x = lson);
    return x;
}
 
int query(int x, int y) {
    return findroot(x) == findroot(y);
}
 
void link(int x, int y) {
    makeroot(x);
    if (findroot(y) != x) fa[x] = y;
}
 
void cut(int x, int y) {
    makeroot(x);
    if (findroot(y) == x && fa[x] == y && tr[y][0] == x && !tr[x][1]) { 
        fa[x] = tr[y][0] = 0;
    }
}
 
int main() {
    int n, m, u, v;
    while (scanf("%d%d", &n, &m) != EOF) {
        memset(fa, 0, sizeof(fa));
        memset(tag, 0, sizeof(tag));
        memset(tr, 0, sizeof(tr));
        for (int i = 0; i < m; i++) {
            scanf("%s", op);
            if (op[0] == 'D') {
                scanf("%d%d", &u, &v);
                cut(u, v);
            }
            else if (op[0] == 'C') {
                scanf("%d%d", &u, &v);
                link(u, v);
            }
            else if (op[0] == 'Q') {
                scanf("%d%d", &u, &v);
                if (query(u, v)) printf("Yes\n");
                else printf("No\n");
            }
        }
    }
    return 0;
}