题目意思很好理解(为什么我会想到查分约束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
最后,要注意如果一开始删完区间后发现灌木丛数一共只有k个了,直接输出就好。注意-1的输出不要忘了。代码如下。
#include
#include
#include
#include
#include
#include
#include
#include
#include
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.Ly.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>1;
if(f[mid].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;
}