关键
感觉是一个很神奇的合并的方法。
首先对这个区间进行左右拆点,然后进行排序处理。
如果加进来的这个点是左端点,那就把在区间里面的左端点进行合并。
如果加进来的是右端点,那就把相对应的左端点进行删除就可以了。
就是没有那些特别复杂的判断了。
这题是检查连通块的数量,所以只需要取最右边的那个点就行了,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;
}
标签:tmp,795,ch,--,CF,int,id,se
From: https://www.cnblogs.com/basicecho/p/17004247.html