CF--795--E

E. Number of Groups

关键

感觉是一个很神奇的合并的方法。
首先对这个区间进行左右拆点,然后进行排序处理。
如果加进来的这个点是左端点,那就把在区间里面的左端点进行合并。
如果加进来的是右端点,那就把相对应的左端点进行删除就可以了。
就是没有那些特别复杂的判断了。
这题是检查连通块的数量,所以只需要取最右边的那个点就行了,set里面存储的东西变一下子就可以了。

代码

#include <bits/stdc++.h>
using namespace std;
using pii=pair<int,int>;
const int M=1e5+5;
#define fi fist
#define se second

inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;
}

struct node {
    int c,l,r;
}a[M];

int fa[M];
int find(int x) {
    return x==fa[x]?fa[x]:fa[x]=find(fa[x]);
}
void merge(int x,int y) {
    fa[find(x)]=find(y);
}

int main() {
    int TT=read();
    while(TT--) {
        int n=read();
        vector<pii>v;
        for(int i=1;i<=n;i++) {
            fa[i]=i;
            a[i].c=read(),a[i].l=read(),a[i].r=read();
            v.push_back({a[i].l,-i});//左边的优先级更高,所以是负的
            v.push_back({a[i].r,i});
        }
        sort(v.begin(),v.end());
        set<pii>se[2];
        for(int i=0;i<v.size();i++) {
            auto [x,id]=v[i];//这个值
            if(id<0) {
                id=-id;//进来
                se[a[id].c].insert({a[id].r,id});
                int tmp=a[id].c^1;//去另一边合并
                while(se[tmp].size()>1) {
                    int y=se[tmp].begin()->second;
                    se[tmp].erase(se[tmp].begin());
                    merge(id,y);
                }
                if(se[tmp].size()==1)merge(se[tmp].begin()->second,id);//这最后一个也要进行合并,其他的全部进行删除
            }
            else se[a[id].c].erase({a[id].r,id});
        }
        int ans=0;
        for(int i=1;i<=n;i++)
            if(fa[i]==i)ans++;
        cout<<ans<<endl;
    }
    return 0;
}
posted @ 2022-12-25 16:57  basicecho  阅读(25)  评论(0)    收藏  举报