2018 UESTC Training for Data Structures--L - 爱吃瓜的伊卡洛斯(2) 启发式合并+并查集+set

L - 爱吃瓜的伊卡洛斯(2)

Time Limit: 1000 MS Memory Limit: 64 MB
Submit Status
伊卡洛斯很爱吃西瓜。一次,他来到一个西瓜摊旁,发现水果摊有
N
N
个西瓜,西瓜有红色、黄色、绿色、蓝色……等等数不清的颜色。 伊卡洛斯很想知道知道一些信息,便于老板交谈了起来。 当老板的话的第一个字符为”A”时,老板会告诉伊卡洛斯一些信息,格式如下:
A x y 1
A x y 1
这句话表示第
x
x
个西瓜和第
y
y
个西瓜是同一种颜色的。
A x y 2
A x y 2
这句话表示第
x
x
个西瓜和第
y
y
个西瓜是不同种颜色的。
当然,为了考验伊卡洛斯有没有认真听, 老板也会时不时问伊卡洛斯一些问题,格式如下:
Q x y
Q x y
这句话表示询问第
x
x
个西瓜和第
y
y
个西瓜是不是同一种颜色,如果确定为同一种颜色,伊卡洛斯需要回答1;确定为不同种颜色,伊卡洛斯需要回答2;无法确定时伊卡洛斯回答3。 注意,伊卡洛斯是根据已获得的信息来回答的。也就是只有这个问题之前的信息才为已知信息。
老板说,只有回答对他全部的问题,伊卡洛斯才能吃到瓜,他聪明的想到了让你来帮助他。
Input
第一行包含两个整数
N
N

M
M

N
N
是西瓜总数,
M
M
是以
A
A

Q
Q
开头的老板的话总和。
以下
M
M
行,每行包含一条老板的话。形式有
A x y 1
A x y 1

A x y 2
A x y 2

Q x y
Q x y

1≤N≤100000 1≤M≤200000 1≤X,Y≤N
1≤N≤100000 1≤M≤200000 1≤X,Y≤N
数据保证没有矛盾
Output
对于每一条
Q
Q
指令,输出1/2/3代表两个西瓜颜色的关系。
Sample input and output
Sample Input
Sample Output
6 9
A 1 2 1
A 1 3 1
A 1 4 2
Q 2 4
Q 1 6
A 3 6 1
A 4 5 2
Q 1 5
Q 1 6
2
3
3
1
Hint
西瓜的颜色可以有无数多种!

思路:这题颜色有无穷多种,所以不能按照普通的并查集分块求对立。
可以用set【】存每一个集合的对立(不同颜色)集合,如果两个x,y颜色相同时,合并两个集合的对立集合。
合并的时候尽量将小的集合合并到大的集合中去。
Code:

#include <bits/stdc++.h>
using namespace std;
const int AX = 1e5+66;
int pre[AX];
set<int>s[AX];
int find1( int x ){
    return x == pre[x] ? pre[x] : pre[x] = find1(pre[x]);
}

void mix( int x , int y ){
    x = find1(x);
    y = find1(y);
    if( x != y ){
        if( s[x].size() > s[y].size() ) swap(x,y);
        pre[x] = y;
        if( s[x].size() ){
            set<int>::iterator it ;
            for( it = s[x].begin() ; it != s[x].end() ; it++ ){
                int tmp = *it;
                s[y].insert(find1(tmp));
            }
        }
    }
    return ;
}

int main(){
    int n , m ;
    scanf("%d%d",&n,&m);
    for( int i = 1 ;  i <= n ; i++ ){
        pre[i] = i;
    }
    char op[5];
    while( m-- ){
        scanf("%s",op);
        int x,y,z;
        if( op[0] == 'A' ){
            scanf("%d%d%d",&x,&y,&z);
            if( z == 1 ){
                mix( x , y );
            }else{
                s[find1(x)].insert(find1(y));
                s[find1(y)].insert(find1(x));
            }
        }else{
            scanf("%d%d",&x,&y);
            int xx = find1(x);
            int yy = find1(y);
            if( s[xx].find(yy) != s[xx].end() || s[yy].find(xx) != s[yy].end() ){
                printf("2\n");
            }else if( find1(x) == find1(y) ){
                printf("1\n");
            }else{
                printf("3\n");
            }
        }
    }
    return  0;
}

另外附测试数据:
4 4
A 1 2 1
A 3 4 1
A 2 4 2
Q 1 3

output : 2

猜你喜欢

转载自blog.csdn.net/frankax/article/details/80297093