在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn]。现在要从中选出 m 个区间,使得这 m个区间共同包含至少一个位置。换句话说,就是使得存在一个 x,使得对于每一个被选中的区间 [li,ri],都有 li≤x≤ri。
对于一个合法的选取方案,它的花费为被选中的最长区间长度减去被选中的最短区间长度。区间 [li,ri] 的长度定义为 ri−li,即等于它的右端点的值减去左端点的值。
求所有合法方案中最小的花费。如果不存在合法的方案,输出 −1。
标签:
比较简单的题
显然先对区间左右端点进行离散化
考虑按区间长度排序,用双指针统计答案
排序后,由于单调性,答案显然是两段连续的区间,那么扫一遍区间,判断多个区间是否有交M即可
用数据结构去维护多个区间求交,显然线段树即可
基本的操作:区间修改,总体查询最大
然后每次到达M更新答案即可
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> using namespace std; int read() { int x=0,f=1; char ch=getchar(); while (ch<‘0‘ || ch>‘9‘) {if (ch==‘-‘) f=-1; ch=getchar();} while (ch>=‘0‘ && ch<=‘9‘) {x=x*10+ch-‘0‘; ch=getchar();} return x*f; } #define MAXN 500100 int N,M,ls[MAXN<<2],tp,top; struct QNode{int l,r,sz;}q[MAXN<<2]; struct SegmentTreeNode{int l,r,tag,maxx;}tree[MAXN<<4]; inline void Update(int now) {tree[now].maxx=max(tree[now<<1].maxx,tree[now<<1|1].maxx);} void Pushdown(int now) { if (!tree[now].tag) return; int D=tree[now].tag; tree[now].tag=0; tree[now<<1].maxx+=D; tree[now<<1|1].maxx+=D; tree[now<<1].tag+=D; tree[now<<1|1].tag+=D; } void Change(int now,int l,int r,int L,int R,int D) { if (L<=l && R>=r) {tree[now].tag+=D; tree[now].maxx+=D; return;} Pushdown(now); int mid=(l+r)>>1; if (L<=mid) Change(now<<1,l,mid,L,R,D); if (R>mid) Change(now<<1|1,mid+1,r,L,R,D); Update(now); } bool cmp(QNode A,QNode B) {return A.sz<B.sz;} int Solve() { int re=0x7fffffff,dfn=0; sort(q+1,q+N+1,cmp); for (int i=1; i<=N; i++) { while (tree[1].maxx<M) { if (dfn==N) return re; dfn++; Change(1,1,top,q[dfn].l,q[dfn].r,1); } re=min(q[dfn].sz-q[i].sz,re); Change(1,1,top,q[i].l,q[i].r,-1); } return re; } int main() { N=read(),M=read(); for (int i=1; i<=N; i++) ls[++tp]=q[i].l=read(),ls[++tp]=q[i].r=read(),q[i].sz=q[i].r-q[i].l; sort(ls+1,ls+tp+1); ls[top]=-1; for (int i=1; i<=tp; i++) if (ls[i]!=ls[top]) ls[++top]=ls[i]; for (int i=1; i<=N; i++) q[i].l=lower_bound(ls+1,ls+top+1,q[i].l)-ls,q[i].r=lower_bound(ls+1,ls+top+1,q[i].r)-ls; int Ans=Solve(); printf("%d\n",Ans==0x7fffffff? -1:Ans); return 0; }
由于同步赛的时候就想到了正解,并且打了一遍,放学前花10分钟又码了一遍...
一开始线段树写了个建树...最后几个点RE成狗.....然后回到最初辣鸡版本,把建树扔了就轻松A了....
被DCrusher大爷嘲讽了一顿
同步赛好像也是这么写的,应该能A?
标签:
原文地址:http://www.cnblogs.com/DaD3zZ-Beyonder/p/5743254.html