• 守卫


    一道大难题

    原著

    好处理的是0区间,把他们删掉,然后重标号。对于0区间在(L)数组中把它并到右边,在(R)数组中把它并到左边。这样的作用是对于1区间,如果它其中包含部分0区间,就可以去掉这些0区间。(说不太清楚,手推一下样例)
    然后对剩下的1区间处理一下(重标号了嘛),排序,去掉包含了小区间的大区间(它没用)。然后借助贪心。。。。
    看代码吧(好像也不是特别理解)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define mid ((l+r)>>1)
    using namespace std;
    const int N = 100005;
    struct node{
    	int l,r,f;
    	bool operator < (const node &cc){
    		return l<cc.l;
    	}
    }a[N];
    int b[N],L[N],R[N],be[N],F[N],G[N];
    int read()
    {
    	char c=getchar();
    	int ans=0,w=1;
    	while((c>'9'||c<'0')&&c!='-') c=getchar();
    	if(c=='-') { w=-1; c=getchar(); }
    	while(c>='0'&&c<='9')
    	{ ans=ans*10+c-'0'; c=getchar(); }
    	return ans*w;
    }
    //bool cmp(node x,node y)
    //{ return x.l<y.l;}
    int main()
    {
    	int n=read(),k=read(),m=read();
    	for(int i=1;i<=m;i++)
    	{
    		a[i].l=read(); a[i].r=read(); a[i].f=read();
    		if(a[i].f==0) ++b[a[i].l],--b[a[i].r+1];
    	}
    	int cur=0,cnt=0;
    	for(int i=1;i<=n;i++)
    	{
    		cur+=b[i];
    		if(cur==0) L[i]=R[i]=++cnt,be[cnt]=i;
    	}
    	if(cnt==k)
    	{
    		for(int i=1;i<=cnt;i++)
    		 printf("%d
    ",be[i]);
    		return 0;
    	}
    	L[n+1]=n+1;
    	for(int i=1;i<=n;i++)
    	 if(R[i]==0) R[i]=R[i-1];
    	for(int i=n;i>=1;--i)
    	 if(L[i]==0) L[i]=L[i+1];
    	cnt=0;
    	for(int i=1;i<=m;i++)
    	{
    		if(a[i].f==0) continue;
    		int l=L[a[i].l],r=R[a[i].r];
    		if(l<=r) a[++cnt].l=l,a[cnt].r=r;
    	}
    	sort(a+1,a+cnt+1);
    	int top=0;
    	for(int i=1;i<=cnt;i++)
    	{
    		while(top&&a[i].l>=L[top]&&a[i].r<=R[top]) --top;
    		L[++top]=a[i].l,R[top]=a[i].r;
    	}
    	int l=n+1,r=0;
    	for(int i=1;i<=top;i++)
    	{
    		if(L[i]>r) F[i]=F[i-1]+1,r=R[i];
    		else F[i]=F[i-1];
    	}
    	for(int i=top;i>=1;i--)
    	{
    		if(R[i]<l) G[i]=G[i+1]+1,l=L[i];
    		else G[i]=G[i+1];
    	}
    	bool ok=0;
    	for(int i=1;i<=top;i++)
    	{
    		if(F[i]==F[i-1]) continue;
    		if(L[i]==R[i]) 
    		{
    			printf("%d
    ",be[R[i]]);
    			ok=1; continue;
    		}
    		int l=1,r=i-1,x=0,y=top+1;
    		while(l<=r)
    		{
    			if(R[mid]<R[i]-1) x=mid,l=mid+1;
    			else r=mid-1;
    		}
    		l=i+1,r=top;
    		while(l<=r)
    		{
    			if(L[mid]>R[i]-1) y=mid,r=mid-1;
    			else l=mid+1;
    		}
    		if(F[x]+G[y]+1>k) 
    		{
    			printf("%d
    ",be[R[i]]);
    			ok=1;
    		}
    	}
    	if(!ok) puts("-1");
    	return 0;
    }
    
  • 相关阅读:
    「ROI 2019 Day1」运输 20/19
    「ROI 2018 Day 2」无进位加法
    「ROI 2018 Day 1」量子隐形传态
    「ROI 2018 Day 2」快速排序
    「ROI 2018 Day 1」Innophone (分块+斜率优化)
    「ROI 2017 Day 1」虎 (计算几何)
    [BJ United Round #3] 押韵 [学习笔记]
    「CEOI2020」象棋世界
    CF1375G
    CF1392(div1+div2)
  • 原文地址:https://www.cnblogs.com/karryW/p/11317463.html
Copyright © 2020-2023  润新知