【复健试手】老年选手的挣扎
作者:互联网
高考结束之后进行简单估分,觉得复读和上带学五五开,所以先把写代码的能力捡起来再说。
如果真的复读了又要停更一年了
这里都是简单题,建议初学者阅读学习。
CF1691E Number of Groups
大意:有一堆红色蓝色的线段,定义不同颜色的线段连通为当且仅当他们至少有一个公共点。问连通团数量。
开始想把线段按照颜色排序后再按照左端点排序,然后建立两棵线段树,对于每条线段在另一种颜色的线段树上找可以连通的线段,然后并查集维护一下并把多余的全都删掉,结果写了一下发现空间复杂度不行(用了一大把 vector )。
思考了一下决定用 set 维护,然后每次在另一个颜色的集合里二分一下始末,再把中间的全都合并,然后删除。复杂度大约是 \(O(nlogn)\) ?(我也不太清楚)
但是发现可以更优化:由于现在线段已经有序,那么可以合并的线段肯定是一块块的。所以只需要维护一个队列,把待合并的扔进去,每次把可以合并的拉出来合并。这样复杂度应该是 \(O(n)\) 的。
调了一个小时才发现加队列的时候颜色挂了
code
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=200005;
int T,n,fa[N],ans,top[2];
struct ky{
int l,r,c;
bool operator < (const ky&p)const{return r^p.r?r<p.r:(l^p.l?l<p.l:c<p.c);}
bool operator == (const ky&p)const{return l==p.l&&r==p.r&&c==p.c;}
}a[N],b[2][N];
int fd(int x){return fa[x]^x?fa[x]=fd(fa[x]):x;}
void mer(int u,int v){u=fd(u),v=fd(v),u^v?--ans,fa[u]=v:0;}
void work(int c,int l,int r,int id){
ky now=(ky) {-1,-1,-1};
if(top[c]) now=b[c][top[c]];
while(top[c]&&b[c][top[c]].r>=l) mer(b[c][top[c]].c,id),--top[c];
now.c!=-1?(((!top[c])||(!(now==b[c][top[c]])))?b[c][++top[c]]=now,0:0):0;
c^=1,b[c][++top[c]]=(ky) {l,r,id};
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d",&n),ans=n,top[0]=top[1]=0;
for(int i=1;i<=n;++i) scanf("%d%d%d",&a[i].c,&a[i].l,&a[i].r),fa[i]=i;
sort(a+1,a+1+n);
for(int i=1;i<=n;++i) work(a[i].c^1,a[i].l,a[i].r,i);
printf("%d\n",ans);
}
return 0;
}
标签:复健,const,复杂度,int,线段,选手,试手,now,top 来源: https://www.cnblogs.com/Kylin-xy/p/16373792.html