「NOI2016」区间 解题报告
「NOI2016」区间
最近思维好僵硬啊...
一上来就觉得先把区间拆成两个端点进行差分,然后扫描位置序列,在每个位置维护答案,用数据结构维护当前位置的区间序列,但是不会维护。
于是想研究性质,想到为什么要拿区间长度做权值呢,难道是有一些性质吗
于是思考了很久区间长度的性质,猜了一些sb结论,比如什么一个区间只有加入时和删除时的贡献算一下就可以了之类的...
全错了然后就自闭了...
然后想什么钦定最大值,然后询问位置区间,然后我发现线段树每个点要挂一个单调队列(事实上把单调队列从线段树上拿下来就是正解了,我当时一点都没想到),然后又自闭了
然后想干脆钦定最大最小值,反正只有\(n^2\)种,然后我们需要查询长度在最大最小值之间的区间,然后我们看一下这些区间的区间并有没有一个位置的值比\(m\)大,区间并可以染色,然后查询最大值
这样可以拿树套树暴力搞了,好像很对
然后发现如果扫描的最大值最小值两个指针的话,移动是\(O(n)\)的,好像叫尺取法把,然后就可以只维护一个线段树了。
Code:
#include <cstdio>
#include <cctype>
#include <algorithm>
using std::max;
const int SIZE=1<<21;
char ibuf[SIZE],*iS,*iT;
#define gc() (iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,SIZE,stdin),iS==iT?EOF:*iS++):*iS++)
//#define gc() getchar()
template <class T>
void read(T &x)
{
x=0;char c=gc();
while(!isdigit(c)) c=gc();
while(isdigit(c)) x=x*10+c-'0',c=gc();
}
void ckmin(int &x,int y){x=x<y?x:y;}
const int inf=0x3f3f3f3f;
const int N=5e5+10;
int n,m,k,saki[N<<1];
struct _toki
{
int l,r,val;
bool friend operator <(_toki a,_toki b){return a.val<b.val;}
}toki[N];
int mx[N<<3],tag[N<<3];
#define ls id<<1
#define rs id<<1|1
void pushdown(int id)
{
if(tag[id])
{
mx[ls]+=tag[id],tag[ls]+=tag[id];
mx[rs]+=tag[id],tag[rs]+=tag[id];
tag[id]=0;
}
}
void upt(int id,int L,int R,int l,int r,int d)
{
if(r<L||l>R) return;
if(l<=L&&R<=r)
{
mx[id]+=d;
tag[id]+=d;
return;
}
pushdown(id);
int Mid=L+R>>1;
upt(ls,L,Mid,l,r,d),upt(rs,Mid+1,R,l,r,d);
mx[id]=max(mx[ls],mx[rs]);
}
int qry(int id,int L,int R,int l,int r)
{
if(r<L||l>R) return 0;
if(l<=L&&R<=r) return mx[id];
pushdown(id);
int Mid=L+R>>1;
return max(qry(ls,L,Mid,l,r),qry(rs,Mid+1,R,l,r));
}
int main()
{
//freopen("data.in","r",stdin);
//freopen("data.out","w",stdout);
read(n),read(k);
for(int i=1;i<=n;i++)
{
read(toki[i].l),read(toki[i].r);
saki[++m]=toki[i].l,saki[++m]=toki[i].r;
toki[i].val=toki[i].r-toki[i].l;
}
std::sort(saki+1,saki+1+m);
m=std::unique(saki+1,saki+1+m)-saki-1;
for(int i=1;i<=n;i++)
{
toki[i].l=std::lower_bound(saki+1,saki+1+m,toki[i].l)-saki;
toki[i].r=std::lower_bound(saki+1,saki+1+m,toki[i].r)-saki;
}
std::sort(toki+1,toki+1+n);
int l=1,r=1,ans=inf;
while(r<=n)
{
upt(1,1,m,toki[r].l,toki[r].r,1);
while(qry(1,1,m,toki[r].l,toki[r].r)>=k)
{
ckmin(ans,toki[r].val-toki[l].val);
upt(1,1,m,toki[l].l,toki[l].r,-1);
++l;
}
++r;
}
if(ans==inf) puts("-1");
else printf("%d\n",ans);
return 0;
}
2019.5.30