51nod 1672 区间交
将右端点放进线段树,然后枚举左端点。
先对l,r排序。因为需要k个区间的相交,所以我们先将前k-1个的区间右端点放进线段树。然后在枚举k到m的时候每次将右端点放入,然后查找边界的最右边。因为l是从小到大排序,所以查找的位置一定是从后往前找第k个的数(这点不懂的可以私我),即叶子节点所以在的位置,注意这个位置一定要在当前左端点的右边!!!然后求最大值就好了。
#include<bits/stdc++.h> #define fp(i,a,b) for(int i=a;i<=b;i++) typedef long long ll; typedef double dl; using namespace std; const int N=2e5+7; const ll M=1e9+7; const int INF=0x3f3f3f3f; ll n,k,m; struct node{ int l,r; }s[N]; struct poi{ int l,r; int sum; }tr[N<<2]; bool cmp(node a,node b) { if(a.l==b.l) return a.r<b.r; return a.l<b.l; } ll a[N],pre[N]; void pushup(int u) { tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum; } void build(int u,int l,int r) { tr[u]={l,r,0}; if(l==r) return ; else { int mid=l+r>>1; build(u<<1,l,mid); build(u<<1|1,mid+1,r); } } void modify(int u,int x) { if(tr[u].l==tr[u].r&&tr[u].r==x) { tr[u].sum++; return ; } int mid=tr[u].l+tr[u].r>>1; if(x<=mid) modify(u<<1,x); else if(x>mid) modify(u<<1|1,x); pushup(u); } int query(int u,int k) { if(tr[u].l==tr[u].r) return tr[u].l; if(tr[u<<1|1].sum>=k) return query(u<<1|1,k); else return query(u<<1,k-tr[u<<1|1].sum); } void solve() { pre[0]=0; scanf("%lld%lld%lld",&n,&k,&m); for(int i=1;i<=n;i++) scanf("%lld",&a[i]),pre[i]=pre[i-1]+a[i]; for(int i=1;i<=m;i++) scanf("%d%d",&s[i].l,&s[i].r); sort(s+1,s+m+1,cmp); build(1,1,n); for(int i=1;i<k;i++) modify(1,s[i].r); ll ans=0; for(int i=k;i<=m;i++) { modify(1,s[i].r); int pos=query(1,k); //printf("pos:%d\n",pos); if(pos>=s[i].l) { ans=max(ans,pre[pos]-pre[s[i].l-1]); //printf("pos:%d\n",pos); } } printf("%lld",ans); } int main() { //ios::sync_with_stdio(0); //cin.tie(0),cout.tie(0); //int T; scanf("%d",&T) //for(int i=1;i<=T;i++) solve(); }