考虑固定右端点,使左端点最小。那么按右端点排序后查询前缀这些区间的左端点第k小即可。然而写了一个treap一个线段树都T飞了,感觉惨爆。事实上可以用堆求第k小,维护一个大根堆保证堆中元素不超过k个即可,瞬间就跑的飞快了。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<queue> using namespace std; #define ll long long #define N 1000010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,ans,u,v; struct data { int l,r,i; bool operator <(const data&a) const { return r<a.r; } }a[N]; priority_queue<int> q; void print(int x,int p) { for (int i=p;i<=n;i++) if (a[i].l<=x) printf("%d ",a[i].i); } int main() { #ifndef ONLINE_JUDGE freopen("bzoj5102.in","r",stdin); freopen("bzoj5102.out","w",stdout); const char LL[]="%I64d "; #else const char LL[]="%lld "; #endif n=read(),m=read(); for (int i=1;i<=n;i++) a[i].l=read(),a[i].r=read(),a[i].i=i; sort(a+1,a+n+1); for (int i=n;i>=1;i--) { q.push(a[i].l); if (n-i+1>=m) { int x=q.top();q.pop(); if (a[i].r-x>ans) u=x,v=i,ans=a[i].r-x; } } cout<<ans<<endl;print(u,v); return 0; }