在这个样例中,有两种可能的安排方式:1,3,5 或者 2,3,5。即 3 和 5
后面必然躲着一个忍者。
考虑第一个灌木丛,存在一种安排方案使得它的后面躲着忍者,但也存在一
种安排方案使得它后面没有躲忍者,因此不应该输出 1。同理,不应该输出 2。
题解:线段树+二分
先扫描所有的区间,用线段树的区间修改将所有监视区间中没有忍者的区间标记,表示这些点中不会有忍者。然后进行线段树的点查询,将所以可能存在忍者的点重新编号,使存在忍者的区间中的编号连续。
然后用o(n)的时间扫出每个点前面第一个有编号的点(即在线段树中没有标记)和后面第一个有编号的点(如果当前点有编号,那么就是自己)
如果剩下的点数等于忍者的个数,那么直接把所有剩下的点输出(注意这里需要特判)
把所有区间按左端点排序,如果一个区间直接包含了某个区间,那么这个区间直接舍去,就可以了(因为满足了小区间就一定满足了大区间)。所以现在的左端点和右端点都是单调的。说明一个问题必须点一定出现在区间右端点,因为右端点一定能属于更多的区间(也就是右端点是最优点,在右端点放能保证忍者数最少,如果最优点都不满足条件,那么一定无解了)。那么就是需要判断区间的右端点是否必须放。首先预处理出f[i]表示前i个区间的最少要放的忍者数(从左到右没有忍者的区间在右端点放一个),g[i]表示后i个区间的最少要放的忍者数。我们就去判断当前区间的右端点x的前一个x-1这个点能否放,放x-1是需要二分一个最大的ans1,b[i].r
#include
#include
#include
#include
#include
#define N 200003
using namespace std;
struct data
{
int l,r,p,mark;
};data ask[N],a[N],b[N];
int n,m,k,delta[N*4],tr[N*4],cnt,s[N],tot;
int pre[N],next[N],f[N],g[N],pos[N],st[N];
void pushdown(int x)
{
if (!delta[x]) return;
delta[x<<1]=delta[x<<1|1]=1;
tr[x<<1]=tr[x<<1|1]=1;
delta[x]=0;
}
void qjchange(int now,int l,int r,int ll,int rr,int v)
{
if (l>=ll&&r<=rr)
{
delta[now]=1;
tr[now]=1;
return ;
}
int mid=(l+r)/2;
if (ll<=mid)
qjchange(now<<1,l,mid,ll,rr,v);
if (rr>mid)
qjchange(now<<1|1,mid+1,r,ll,rr,v);
}
bool query(int now,int l,int r,int x)
{
if (l==r) return tr[now];
int mid=(l+r)/2;
pushdown(now);
if(x<=mid)
return query(now<<1,l,mid,x);
else
return query(now<<1|1,mid+1,r,x);
}
void point()
{
for (int i=1;i<=n;i++)
if (!query(1,1,n,i))
s[i]=++tot,pos[tot]=i;
}
int cmp(data a,data b)
{
return a.lb.r;
}
int main()
{
scanf("%d%d%d",&n,&k,&m);
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&ask[i].l,&ask[i].r,&ask[i].p);
if (!ask[i].p)
qjchange(1,1,n,ask[i].l,ask[i].r,1);
}
point();
if (tot==k)
{
for (int i=1;i<=n;i++)
if (s[i])
printf("%d\n",i);
return 0;
}
int t=0;
for (int i=1;i<=n;i++)
{
if (s[i]) t=i;
pre[i]=t;
}
t=n+1;
for (int i=n;i>=1;i--)
{
if (s[i]) t=i;
next[i]=t;
}
for (int i=1;i<=m;i++)
if (ask[i].p)
{
cnt++,a[cnt].l=s[next[ask[i].l]],a[cnt].r=s[pre[ask[i].r]];
if (a[cnt].l>a[cnt].r)
cnt--;
}
sort(a+1,a+cnt+1,cmp);
int top=1; st[top]=1;
for (int i=2;i<=cnt;i++)
{
while (a[i].r<=a[st[top]].r&&top)
top--;
st[++top]=i;
}
for (int i=1;i<=top;i++)
b[i].l=a[st[i]].l,b[i].r=a[st[i]].r;
int mx=0,mn=tot+1;
for (int i=1;i<=top;i++)
if (b[i].l>mx)
f[i]=f[i-1]+1,mx=b[i].r;
else
f[i]=f[i-1];
for (int i=top;i;i--)
if (b[i].rx) ans2=mid,r=mid-1;
else l=mid+1;
}
if (f[ans1]+g[ans2]+1>k)
{
flag=1;
printf("%d\n",pos[b[i].r]);
}
}
if (!flag)
printf("-1\n");
return 0;
}