CodeCraft-22 and Codeforces Round #795 (Div. 2) E(并查集+扫描线)

CodeCraft-22 and Codeforces Round #795 (Div. 2) E(并查集+扫描线)

题意:

\(n\) 个线段,线段要么是红色要么蓝色。现在要对线段进行合并。只有有区间重叠的才能合并,合并要求红区间只能直接的并入蓝区间,蓝区间只能直接的并入红区间。问最后会分成多少堆。

思路:

感觉上是想办法用并查集维护这个合并过程。

因为有颜色限制,肯定不能直接写。先来分析这干了什么事。

考虑一个线段 \([l,r]\),这个线段可以合并所有异色有重合的线段。这些异色的线段可以开两个集合存,当这个线段结束,就从集合中弹出。

但此时还有一个问题就是,对 集合中的一条线段很可能出现多次合并的情况,所以肯定要把重复操作剪掉。还是和并查集类似的思想,用一个线段表示整个集合,这里需要使用最靠右的线段表示整个集合。

最后就是代码实现上,用的是扫描线的思想,把线段拆成两个事件,一个活动,一个结束,从左往右扫,遇到活动的就将之放入集合,做并查集的合并,遇到结束,就把线段从集合中删除。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
#include<queue>
#include<map>
#include<string>
#include<random>
#define yes puts("yes");
#define inf 0x3f3f3f3f
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define ull unsigned long long
#define endl '\n'
#define int long long
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
using namespace std;
mt19937 mrand(random_device{}());
int rnd(int x) { return mrand() % x;}
typedef pair<int,int> PII;
const int MAXN =10 + 2e5 ,mod=1e9 + 7;
struct Node {
    int id,col,p,t;
};
int R[MAXN];
int fa[MAXN];
struct Cmp {
        bool operator() (const int a,const int b) const{
        if(R[a] != R[b]) return R[a] < R[b];
        return a<b;//一定要判R[a] == R[b] 不然会错
    }
};

int root(int x) {
    return fa[x] == x ? x : (fa[x] = root(fa[x]));
}
void unite(int x,int y) {
    x = root(x) , y = root(y);
    if(x == y) return;
    fa[x] = y;
}
void solve()
{    
    int n; cin >> n;
    vector<Node> a;
    
    rep(i,1,n) {
        fa[i] = i;
        int c,l,r; cin >> c >> l >> r;
        R[i] = r;
        a.push_back({i,c,l,0});
        a.push_back({i,c,r,1});
    }
    sort(a.begin(),a.end(),[&](Node x,Node y) {
        if(x.p != y.p) return x.p < y.p;
        return x.t < y.t;
    });
    int m = a.size();
    
    
    set<int,Cmp> s0,s1;
    rep(i,0,m - 1) {
        auto [id,col,p,t] = a[i];
        // cout << id << " " << p << " " << (t ? 'r' : 'l') << endl;
        if(t == 0) {
            if(!col) {
                s0.insert(id);
                while(s1.size() > 1) {
                    unite(*s1.begin(), id);
                    s1.erase(s1.begin());
                }
                if(!s1.empty()) unite(*s1.begin(), id);
            }else {
                s1.insert(id);
                while(s0.size() > 1) {
                    unite(*s0.begin(), id);
                    s0.erase(s0.begin());
                }
                if(!s0.empty()) unite(*s0.begin(),id);
            }
        }else {
            if(!col) {
                s0.erase(id);
                
            }else {
                s1.erase(id);
            }
        }
    }
    vector<int> sz(n + 1);
    rep(i,1,n) sz[root(i)] ++;
    int ans = 0;
    rep(i,1,n) ans += (sz[i] != 0);
    cout << ans << endl;
}
signed main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

    int T;cin>>T;
    while(T--)
        solve();

    return 0;
}
posted @ 2022-06-08 23:07  Mxrurush  阅读(24)  评论(0编辑  收藏  举报