一开始以为是差分约束yy了个结论WA了qwq,虽然至今还不知道为什么那个结论不对
先将序列中不可能有忍者的位置标出来
如果剩下的位置恰好有K个,要特判直接全部输出
然后将每个区间缩掉两端的0
如果存在某两个区间A,B,A包含B,那么A是不必要的
处理完后剩下的区间两两互不包含,按右端点排序后,从左到右左右端点递增
易知只有每个区间的右端点有可能一定有忍者,因为贪心的放肯定是放右端点更优
用f[i]表示保证了1~i区间的限制最少需要几个忍者,g[i]表示保证了i~n的区间限制至少需要几个忍者,F[i]表示i位置一定有忍者,保证所有限制,至少需要几个忍者
f[i]和g[i]可以简单的做两个贪心得到,F[i]用两个指针找i向左第一个不能覆盖的区间,向右第一个不能覆盖的区间,O(n)扫过去得到
然后从左到右扫区间,维护一个单调队列,对于每个区间[l,r],维护[l,r)(左闭右开)内F[i]的最小值,如果这个最小值<=K,就代表右端点不是必须取的
标记,缩区间可以用并查集做到O(n)
dp,判断都可以做到O(n)
所以除去排序的复杂度是O(n)的,排序可以用桶排做到总复杂度O(n)
(然而跑的和nlogn的线段树一样快并没有什么用qwq
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = 210000;
const int maxm = 210000;
int n,m,K;
struct node { int l,r; }a[maxm]; int cnt;
inline bool cmp(const node x,const node y){return x.r==y.r?x.l>y.l:x.r<y.r;}
int fal[maxn],far[maxn],s[maxn];
int findfa(int fa[],const int x){return fa[x]==x?x:fa[x]=findfa(fa,fa[x]);}
int f[maxn],g[maxn],F[maxn];
int q[maxn],head,tail;
int ans[maxn],tp;
int main()
{
scanf("%d%d%d",&n,&K,&m);
for(int i=1;i<=n;i++) fal[i]=far[i]=i,s[i]=1; far[n+1]=n+1;
for(int i=1;i<=m;i++)
{
int l,r,c; scanf("%d%d%d",&l,&r,&c);
if(!c)
{
int j=l;
while(j<=r)
{
j=findfa(far,j);
if(j<=r) s[j]=0,far[j]=j+1;
}
j=r;
while(j>=l)
{
j=findfa(fal,j);
if(j>=l) s[j]=0,fal[j]=j-1;
}
}
else a[++cnt]=(node){l,r};
}
int oth=0; for(int i=1;i<=n;i++) oth+=s[i];
if(oth==K)
{
for(int i=1;i<=n;i++) if(s[i]) printf("%d\n",i);
return 0;
}
for(int i=1;i<=cnt;i++)
a[i].l=findfa(far,a[i].l),a[i].r=findfa(fal,a[i].r);
sort(a+1,a+cnt+1,cmp);
int temp=0;
for(int i=1;i<=cnt;i++)
if(a[i].l>a[temp].l) a[++temp]=a[i];
cnt=temp;
int r=a[1].r; f[1]=1;
for(int i=2;i<=cnt;i++)
{
if(a[i].l<=r) f[i]=f[i-1];
else f[i]=f[i-1]+1,r=a[i].r;
}
int l=a[cnt].l; g[cnt]=1;
for(int i=cnt-1;i>=1;i--)
{
if(a[i].r>=l) g[i]=g[i+1];
else g[i]=g[i+1]+1,l=a[i].l;
}
l=0,r=2; oth=1;
for(;oth<=n;oth++)
{
while(a[l+1].r<oth&&l<cnt) l++;
while(r<=cnt&&oth>=a[r].l) r++;
F[oth]=f[l]+g[r]+1;
}
head=1,tail=0; r=0;
for(int i=1;i<=cnt;i++)
{
while(r+1<a[i].r)
{
++r;
if(s[r])
{
while(head<=tail&&F[q[tail]]>=F[r]) tail--;
q[++tail]=r;
}
}
while(head<=tail&&q[head]<a[i].l) head++;
if(head>tail||F[q[head]]>K) ans[++tp]=a[i].r;
}
if(!tp) puts("-1");
//for(int i=1;i<=cnt;i++) printf("%d %d\n",a[i].l,a[i].r); puts("");
for(int i=1;i<=tp;i++) printf("%d\n",ans[i]);
return 0;
}