CF1956F Nene and the Passing Game 解题报告

假设 j>i ,则:i+lijlj,i+rijrj

所以相当于看区间 [i+li,i+ri] 和区间 [jrj,jlj] 是否有交集

可以将这些区间放在数轴上,考虑建虚点,将数轴上的每个点向包含它的区间连边

但是这样会有一个问题,记加为右区间,减为左区间,此时就无法判断是哪种区间在相交

所以可以只保留既有左区间又有右区间覆盖的点,这样就能保证一定是符合条件的

但是依次对每个点连边显然会T,考虑优化

先用 prene 记录前/后满足条件的最近的点

对于区间 [l,r],操作就应在 [nel,prer]

利用差分的思想,统计数轴上每个点被覆盖且不为末端点的次数

因为作为末端点,后面没有与之相邻的点,就无法向后合并

如果次数不为0,就向后连边,最后看有多少连通块即可

代码:

#include<cstdio>
#include<algorithm>
using namespace std;
int T,n,l[2000006],r[2000005],pre[2000005],ne[2000006];
int cntl[2000006],cntr[2000006],f[4000006],tot;
int v[2000005];
int find(int x)
{
	if(f[x]!=x) f[x]=find(f[x]);
	return f[x];
}
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		tot=0;
		for(int i=0;i<=n;i++)
		{
			cntl[i]=cntr[i]=0;
			pre[i]=ne[i]=v[i]=0;
		}
		for(int i=1;i<=n;i++)
		{
			scanf("%d%d",&l[i],&r[i]);
			cntl[max(1,i-r[i])]++;
			cntl[max(1,i-l[i]+1)]--;
			cntr[min(n,i+l[i])]++;
			cntr[min(n,i+r[i]+1)]--;
			f[i]=i;
		}
		for(int i=1;i<=n;i++)
		{
			cntl[i]+=cntl[i-1];
			cntr[i]+=cntr[i-1];
			if(cntl[i]&&cntr[i])
			{
				pre[i]=ne[i]=++tot;
				f[n+tot]=tot+n;
			}
			
			else
			{
				pre[i]=pre[i-1];
			}
		}
		ne[n+1]=1e9;
		for(int i=n;i>0;i--)
		{
			if(!ne[i]) ne[i]=ne[i+1];
		}
		for(int i=1;i<=n;i++)
		{
			int ql=ne[max(1,i-r[i])];
			int qr=pre[max(0,i-l[i])];
			if(ql<=qr)
			{
				v[ql]++,v[qr]--;
				f[find(i)]=find(qr+n);
			}
			ql=ne[min(n+1,i+l[i])];
			qr=pre[min(n,i+r[i])];
			if(ql<=qr)
			{
				v[ql]++,v[qr]--;
				f[find(i)]=find(qr+n);
			}
//			printf("%d",i);
		}
		for(int i=1;i<=tot;i++)
		{
			v[i]+=v[i-1];
		}
		for(int i=1;i<=tot;i++)
		{
			if(v[i])
			{
				f[find(i+n)]=find(n+i+1);
			}
		}
		int ans=0;
		for(int i=1;i<=n+tot;i++)
		{
			if(f[i]==i) ans++;
		}
		printf("%d\n",ans);
	}
	return 0;
}
posted @   wangsiqi2010916  阅读(13)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示