bzoj2811 apio2012 守卫 guard 贪心

来源:互联网 发布:word文档下载mac版 编辑:程序博客网 时间:2024/04/28 04:32

    题目意思很好理解(为什么我会想到查分约束QAQ) ,正解居然是贪心(apio和noi/noip系列确实还是赶脚不一样)

    首先要做的是把一定没有忍者的区间删除。用线段树操作比较方便,之后给每一个没被删除位置(从1---n)一个新的编号,

为了将读入的区间重新表示出来(即要使读入的L,R都应该在没被删的地方),假设区间为(L,R),如果L所处被删,自然应该去找L右边第一个没被删的,R则为左边。两次扫描就可以得到,注意不要那些已经被彻底删完了的区间。

    转回来想问题,其实就是类似于区间覆盖,会有一些灌木丛很优,能同时满足多个要求,那么大体思路是如果假设不选一个灌木丛,而其灌木丛最少需要的忍者数加起来超过了 k 的限制,那么这个被假设的灌木丛一定得选。

    用区间覆盖来解决这个问题,当把区间按左端点排序后,去掉具有包含关系的区间中大的那一个(满足了小区间就一定满足大区间),(这样所有区间左右端点都单增了)每次在一个区间的右端点放一个忍者,(这样能保证使用忍者数量最少),多余的忍者随便放即可满足,这里可以看到一个性质,就是只有区间的右端点才有可能成为必须点(理解 多余的随便放),那么现在要做的就是判断一个区间的右端点(R)是否必须放。令F[i]表示i及其之前的位置最少放多少个忍者,G[i]表示i及其之后的位置最少放多少个忍者,我们就去判断R-1这个点能否放(R-1比R-2优),放R-1是需要二分一个最大的k1,f[k1].R <R-1,一个最小的k2,使f[k2].L>R-1,F[k1]+G[k2]+1即为当前的忍者需要量,如果大于k,说明R这个位置如果不放,就一定无法只用k个忍者来满足这些限制要求,所以R是必须的,输出其原始位置。

   最后,要注意如果一开始删完区间后发现灌木丛数一共只有k个了,直接输出就好。注意-1的输出不要忘了。代码如下。

#include<iostream>#include<set>#include<cmath>#include<queue>#include<cstdio>#include<bitset>#include<cstdlib>#include<cstring>#include<algorithm>using namespace std;typedef long long LL;const int N=400005,INF=0x7fffffff/2;struct Data{int L,R,k;}a[N],q[N],f[N];int n,m,k,jud[N],Ls[N],Rs[N],cnt=0,To[N],num=0,top=0;int F[N],G[N];void Sub(int v,int L,int R,int x,int y){int mid=(L+R)>>1;if(x<=L&&R<=y){jud[v]=1;return;}if(x<=mid)Sub(2*v,L,mid,x,y);if(y>mid)Sub(2*v+1,mid+1,R,x,y);}bool Ask(int v,int L,int R,int pos){if(jud[v])return 1;int mid=(L+R)>>1;if(L==R)return 0;if(pos<=mid)return Ask(2*v,L,mid,pos);return Ask(2*v+1,mid+1,R,pos);}bool cmp(const Data x,const Data y){return x.L<y.L||(x.L==y.L&&x.R>y.R);}int main(){scanf("%d%d%d",&n,&k,&m);int x,y,i,j;for(i=1;i<=m;i++){scanf("%d%d%d",&a[i].L,&a[i].R,&a[i].k);if(!a[i].k)Sub(1,1,n,a[i].L,a[i].R);}for(i=1;i<=n;i++)  if(!Ask(1,1,n,i))Ls[i]=Rs[i]=++cnt,To[cnt]=i;if(cnt==k){for(i=1;i<=cnt;i++)printf("%d\n",To[i]);return 0;}Ls[0]=0;    for(i=1;i<=n;i++)if(!Ls[i])Ls[i]=Ls[i-1];    Rs[n+1]=INF;    for(i=n;i>=1;i--)if(!Rs[i])Rs[i]=Rs[i+1];for(i=1,num=0;i<=m;i++) if(a[i].k) { x=Rs[a[i].L];y=Ls[a[i].R]; if(x<=y)q[++num]=(Data){x,y,0}; }sort(q+1,q+num+1,cmp);for(i=1,top=0;i<=num;i++){while(top>=1&&f[top].L<=q[i].L&&q[i].R<=f[top].R)top--;f[++top]=q[i];}int Max=0,Min=INF;for(i=1;i<=top;i++) if(f[i].L>Max)F[i]=F[i-1]+1,Max=f[i].R; else F[i]=F[i-1];for(i=top;i>=1;i--) if(f[i].R<Min)G[i]=G[i+1]+1,Min=f[i].L; else G[i]=G[i+1];bool SPE=0;int L,R,mid,k1,k2;for(i=1;i<=top;i++){if(F[i]!=F[i-1]+1)continue;if(f[i].L==f[i].R){SPE=1;printf("%d\n",To[f[i].L]);continue;}x=f[i].R-1;k1=0;k2=top+1;L=1;R=i-1;while(L<=R){mid=(L+R)>>1;if(f[mid].R<x)k1=mid,L=mid+1;else R=mid-1;}L=i+1;R=top;while(L<=R){mid=(L+R)>>1;if(f[mid].L>x)k2=mid,R=mid-1;else L=mid+1;}if(F[k1]+G[k2]+1>k){SPE=1;printf("%d\n",To[f[i].R]);}}if(!SPE)printf("-1");return 0;}


1 0