題解 [NOI2016] 區間
阿新 • • 發佈:2021-08-30
題意
題目連結:傳送門
題面比較簡潔了。
碎碎念
開學前一天頹著頹著就看到這道題了
一開始想了一個假的做法:用一顆線段樹維護 \([L,R]\) 的最小花費和最大權值,大概寫了
\(30min\)之後發現沒辦法維護最大最小區間長........
然後 看了一眼題解看到了尺取法這三個字,又看了看標籤裡有排序,然後就沒有然後了———
Solution
首先注意到一個性質:增加一個區間不會使答案更優,去掉一個區間不會使答案變差
進而注意到對於一個區間的集合 \(S\),令\(min(S)=a,max(S)=b\),則長度在\([a,b]\)中的區間對答案沒有影響,也就是說它們是可有可無的。
於是我們得出一個結論,最優解的所有區間長度必然可以
按區間長度升序將所有區間排序,然後雙指標掃掃一遍,右指標向前掃,不斷更新區間最大值,當這個最大值(也就是區間內一個點被覆蓋最多次數)大於等於\(m\)時,左指標向前走直到區間最大又小於\(m\)
顯然區間最值可以用線段樹維護,總的複雜度\(O(nlogn)\)
#include<bits/stdc++.h> #define rep(a,b,c) for (register int a=b;a<=c;a++) #define per(a,b,c) for (register int a=b;a>=c;a--) using namespace std; typedef long long ll; template <typename T> inline void read(T &x){ ll f = 1;x = 0;char ch = getchar(); while (!isdigit(ch)){if (ch == '-')f = -1;ch = getchar();} while (isdigit(ch)){x = (x << 1)+(x << 3)+(ch ^ 48);ch = getchar();} x *= f; } const int MAXN=500100; int n,m; int b[MAXN*2],cnt,tot; struct Section{ int x,y,len; bool operator < (const Section &X) const { return len==X.len?x<X.x:len<X.len; } }a[MAXN]; struct Segtree { struct node { int l,r,maxv,tag; #define l(i) tree[i].l #define r(i) tree[i].r #define maxv(i) tree[i].maxv #define tag(i) tree[i].tag }tree[MAXN*8]; inline void build(int pos,int L,int R) { maxv(pos)=0; l(pos)=L,r(pos)=R; if(L==R) return; int mid=l(pos)+r(pos)>>1; build(pos<<1,L,mid); build(pos<<1|1,mid+1,R); } inline void push_up(int pos) { maxv(pos)=max(maxv(pos<<1),maxv(pos<<1|1)); } inline void push_down(int pos) { maxv(pos<<1)+=tag(pos),maxv(pos<<1|1)+=tag(pos); tag(pos<<1)+=tag(pos),tag(pos<<1|1)+=tag(pos); tag(pos)=0; } inline void modify(int pos,int L,int R,int val) { if(l(pos)>=L&&r(pos)<=R) { maxv(pos)+=val; tag(pos)+=val; return; } if(l(pos)==r(pos))return; if(tag(pos))push_down(pos); int mid=l(pos)+r(pos)>>1; if(L<=mid)modify(pos<<1,L,R,val); if(R>mid)modify(pos<<1|1,L,R,val); push_up(pos); } }T; inline void init() { scanf("%d%d",&n,&m); rep(i,1,n) { scanf("%d%d",&a[i].x,&a[i].y); b[++tot]=a[i].x,b[++tot]=a[i].y; a[i].len=a[i].y-a[i].x; } sort(a+1,a+n+1); sort(b+1,b+tot+1); cnt=unique(b+1,b+tot+1)-b-1; } inline void solve() { T.build(1,1,cnt); int lpos,rpos; lpos=rpos=1; int ans=1e9; while(lpos<=rpos&&rpos<=n) { int L=lower_bound(b+1,b+cnt+1,a[rpos].x)-b; int R=lower_bound(b+1,b+cnt+1,a[rpos].y)-b; T.modify(1,L,R,1); while(T.maxv(1)>=m&&lpos<rpos) { ans=min(ans,a[rpos].len-a[lpos].len); int tL=lower_bound(b+1,b+cnt+1,a[lpos].x)-b; int tR=lower_bound(b+1,b+cnt+1,a[lpos].y)-b; T.modify(1,tL,tR,-1); ++lpos; } ++rpos; } if(ans!=1e9)printf("%d\n",ans); else printf("-1\n"); } int main() { init(); solve(); return 0; } `