The Preliminary Contest for ICPC Asia Xuzhou 2019 B. so easy (unordered_map + 并查集)

题目链接:https://nanti.jisuanke.com/t/41384

题意:给你一个n代表你拥有了n个数,有q个操作,op=1  x  是使得x不可被利用,op = 2  x 是查询[x, n]中,第一个可被利用的是谁(n<= 1e9)

当时做题的时候,根本没想到暴力会过,数据太水了,我tm二分加树状数组都超时,他们一个unordered_map暴力过了?

不过正解是并查集+离线处理,可以发现,你删除一个数x,那么x+1一定是当前可被利用的最小的数,所以只需要记录被删除的点和被删除点+1位置的点即可,还有需要加上需要查询的点,因为最终结果可能是他本身

这样对于每个操作,如果是删除,就让当前x和x+1连在一起,否则就输出当前x的父亲节点

#include 
#include 
using namespace std;
typedef long long ll;
const int maxn = 1e6+10;
struct  node{
    int op, x;
}pos[maxn];
unordered_map mp;
int getf(int x){
    return x == mp[x] ? x : mp[x] = getf(mp[x]);
}
void merg1e(int x, int y){
    int t1 = getf(x);
    int t2 = getf(y);
    if(t1 != t2) {
        mp[t1] = t2;
    }
}
int main(){
    int n, q;
    scanf("%d%d", &n, &q);
    for(int i = 0; i < q; i++) {
        scanf("%d%d" ,&pos[i].op, &pos[i].x);
        if(pos[i].op == 1){
            mp[pos[i].x] = pos[i].x;
            mp[pos[i].x + 1] = pos[i].x + 1;
        }
        else mp[pos[i].x] = pos[i].x;
    }
    for(int i = 0; i < q; i++) {
        if(pos[i].op == 1) merg1e(mp[pos[i].x], mp[pos[i].x + 1]);
        else printf("%d\n", getf(mp[pos[i].x]));
    }
    return 0;
}

 

你可能感兴趣的:(并查集,stl)