非常考分析能力的一个题目。
因为这个答案是满足单调性的,可以二分,转化成判定性问题之后。这么考虑,如果把所有的询问按照回答降序排列,然后每处理一个询问的时候,先看它的区间是否被完全覆盖,如果是,则矛盾,否则把它的区间覆盖。
解释一下,每次覆盖的时候,意思就是这个位置不能放更小的值,如果有一次询问区间没有空白的位置,证明这个值没有办法放进去。所以矛盾。反之,我们每次都任意找一空白处放进一个值,肯定能构造出解。
但是,这个题目还要求值是唯一的,所以要一次处理所以相同的值,求交集,如果交集为空,矛盾。否则,查看交集,覆盖并集。
到这里还有问题,这个题目的范围很大,要离散化,离散化还有一个问题,离散化后的相邻的两个值可能离散化前不相邻,那么覆盖了这两个端点后其实没有覆盖这个区间。
所以离散化的时候要对这样的点中间空出一个值。
代码如下
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ls (t<<1)
#define rs (t<<1|1)
#define midt (tr[t].l+tr[t].r>>1)
using namespace std;
const int maxn=25000+9;
int n,q;
int N;
struct D
{
int id,key;
bool operator <(const struct D & xx) const
{
return key<xx.key;
}
}a[maxn<<1];
struct Q
{
int l,r,min;
bool operator <(const struct Q &xx) const
{
return min>xx.min;
}
}qry[maxn],now[maxn];
struct
{
int l,r;
bool data;
}tr[maxn<<4];
void maketree(int t,int l,int r)
{
tr[t].l=l;
tr[t].r=r;
tr[t].data=0;
if(l==r) return;
int mid=midt;
maketree(ls,l,mid);
maketree(rs,mid+1,r);
}
void pushdown(int t)
{
if(tr[t].data==1)
{
tr[ls].data=tr[rs].data=1;
}
}
bool query(int t,int l,int r)
{
if(l==tr[t].l&&r==tr[t].r)
return tr[t].data;
pushdown(t);
int mid=midt;
if(r<=mid) return query(ls,l,r);
else if(mid+1<=l) return query(rs,l,r);
else
{
bool fla=1;
if(query(ls,l,mid)==0) fla=0;
if(query(rs,mid+1,r)==0) fla=0;
return fla;
}
}
void modify(int t,int l,int r)
{
if(l==tr[t].l&&r==tr[t].r)
{
tr[t].data=1;
return ;
}
pushdown(t);
int mid=midt;
if(r<=mid) modify(ls,l,r);
else if(mid+1<=l) modify(rs,l,r);
else
{
modify(ls,l,mid);
modify(rs,mid+1,r);
}
if(tr[ls].data&&tr[rs].data) tr[t].data=1;
else tr[t].data=0;
}
bool chk(int ret)
{
// cout<<ret<<endl;
for(int i=1;i<=ret;i++)
now[i]=qry[i];
sort(now+1,now+ret+1);
maketree(1,1,N);
for(int i=1,j;i<=ret;i=j)
{
int l=now[i].l,r=now[i].r;
j=i+1;
while(j<=ret&&now[j].min==now[i].min)
{
if(l>now[j].r||now[j].l>r) return false;
l=max(l,now[j].l);
r=min(r,now[j].r);
j++;
}
if(query(1,l,r)) return false;
for(int k=i;k<j;k++)
modify(1,now[k].l,now[k].r);
}
return true;
}
int main()
{
// freopen("in.txt","r",stdin);
while(scanf("%d %d",&n,&q)!=EOF)
// scanf("%d %d",&n,&q);
{
N=q<<2;
for(int i=1;i<=q;i++)
{
scanf("%d %d %d",&qry[i].l,&qry[i].r,&qry[i].min);
if(qry[i].l>qry[i].r)
swap(qry[i].l,qry[i].r);
a[i*2].id=i*2;
a[i*2].key=qry[i].l;
a[i*2+1].id=i*2+1;
a[i*2+1].key=qry[i].r;
}
sort(a+2,a+q+q+2);
a[1].key=-1;
int lon=0;
for(int i=2;i<=q+q+1;i++)
{
if(a[i].key!=a[i-1].key)
{
lon++;
if(a[i].key!=a[i-1].key+1)
lon++;
}
if(a[i].id&1) qry[a[i].id/2].r=lon;
else qry[a[i].id/2].l=lon;
}
int st=1,ed=q,mid;
while(st<ed)
{
// printf("%d %d\n",st,ed);
mid=st+ed>>1;
if(chk(mid)) st=mid+1;
else ed=mid;
}
if(st==q&&chk(st))
printf("0\n");
else
printf("%d\n",st);
}
return 0;
}