uva 6910 - Cutting Tree 并查集的删边操作,逆序

https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4922

题意是给定一颗森林,然后每次都可以删除一条边,或者询问某两个点是否连通。

如果顺着做是不行的。因为并查集路径压缩了,是删不了边的,(据说不路径压缩能AC,)

所以考虑逆向操作。首先不能把已经删除了的边加进去森林里面,先处理出最终状态,然后倒着模拟,就能把删边操作等价于变成加边操作了。注意有一点坑得地方就是,多次删除某一条边,那么你只能在第一次删除这条边的地方把这条边建立起来,

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;


#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <bitset>
const int maxn = 20000 + 20;
int fa[maxn], baba[maxn];
int tofind(int u) {
    if (fa[u] == u) return u;
    else return fa[u] = tofind(fa[u]);
}
void tomerge(int x, int y) {
    if (x == 0) return;
    if (y == 0) while(1);
    x = tofind(x);
    y = tofind(y);
    fa[y] = x;
}
struct Node {
    char ch;
    int a, b;
}query[maxn];
bool ans[maxn];
int del[maxn];
void init() {
    for (int i = 1; i <= maxn - 2; ++i) fa[i] = i;
    memset(del, false, sizeof del);
    memset(ans, false, sizeof ans);
}
int f;
void work() {
    init();
    int n, q;
    cin >> n >> q;
    for (int i = 1; i <= n; ++i) {
        cin >> baba[i];
    }
    for (int i = 1; i <= q; ++i) {
        char str[22];
        cin >> str;
        query[i].ch = str[0];
        if (str[0] == 'C') {
            cin >> query[i].a;
            if (del[query[i].a]) continue;
            else del[query[i].a] = i;
        } else {
            cin >> query[i].a >> query[i].b;
        }
    }
    for (int i = 1; i <= n; ++i) {
        if (del[i]) continue;
        tomerge(baba[i], i);
    }
    for (int i = q; i >= 1; --i) {
        if (query[i].ch == 'C') {
            if (del[query[i].a] != i) continue;
            tomerge(baba[query[i].a], query[i].a);
            continue;
        }
        int x = tofind(query[i].a);
        int y = tofind(query[i].b);
        if (x == y) {
            ans[i] = true;
        }
    }
    printf("Case #%d:\n", ++f);
    for (int i = 1; i <= q; ++i) {
        if (query[i].ch == 'C') continue;
        if (ans[i]) {
            printf("YES\n");
        } else printf("NO\n");
    }
}


int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
    int t;
    scanf("%d", &t);
    while (t--) work();
    return 0;
}
View Code

 

 1 
2 1
0 0
Q 1 2
 
 1
4 3
0 1 2 2
C 2 
Q 2 1
C 2
 
 1 
2 3
0 0
Q 1 2
C 1
C 2

posted on 2017-03-05 20:44  stupid_one  阅读(388)  评论(0编辑  收藏  举报

导航