ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【复健试手】老年选手的挣扎

2022-06-14 12:04:39  阅读:146  来源: 互联网

标签:复健 const 复杂度 int 线段 选手 试手 now top


高考结束之后进行简单估分,觉得复读和上带学五五开,所以先把写代码的能力捡起来再说。如果真的复读了又要停更一年了

这里都是简单题,建议初学者阅读学习。

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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有