非常考分析能力的一个题目。
因为这个答案是满足单调性的,可以二分,转化成判定性问题之后。这么考虑,如果把所有的询问按照回答降序排列,然后每处理一个询问的时候,先看它的区间是否被完全覆盖,如果是,则矛盾,否则把它的区间覆盖。
解释一下,每次覆盖的时候,意思就是这个位置不能放更小的值,如果有一次询问区间没有空白的位置,证明这个值没有办法放进去。所以矛盾。反之,我们每次都任意找一空白处放进一个值,肯定能构造出解。
但是,这个题目还要求值是唯一的,所以要一次处理所以相同的值,求交集,如果交集为空,矛盾。否则,查看交集,覆盖并集。
到这里还有问题,这个题目的范围很大,要离散化,离散化还有一个问题,离散化后的相邻的两个值可能离散化前不相邻,那么覆盖了这两个端点后其实没有覆盖这个区间。
所以离散化的时候要对这样的点中间空出一个值。
代码如下
#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 ",st,ed); mid=st+ed>>1; if(chk(mid)) st=mid+1; else ed=mid; } if(st==q&&chk(st)) printf("0 "); else printf("%d ",st); } return 0; }