区间交
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1162 Accepted Submission(s): 456
Problem Description
小A有一个含有n个非负整数的数列与m个区间。每个区间可以表示为li,ri。
它想选择其中k个区间, 使得这些区间的交的那些位置所对应的数的和最大。
例如样例中,选择[2,5]与[4,5]两个区间就可以啦。
Input
多组测试数据
第一行三个数n,k,m(1≤n≤100000,1≤k≤m≤100000)。
接下来一行n个数ai,表示lyk的数列(0≤ai≤109)。
接下来m行,每行两个数li,ri,表示每个区间(1≤li≤ri≤n)。
Output
一行表示答案
Sample Input
5 2 3
1 2 3 4 6
4 5
2 5
1 4
Sample Output
10
思路:我们按照右区间从大到小排序,那么我们可以枚举当前K个及以上的区间,从这里面选取K个,这K个里面左端点肯定是越小越好,那么就是当前的第K小了,可用线段树来维护更新
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=1e5+10; 5 6 struct node{ 7 int x,y; 8 }a[N]; 9 ll s[N]; 10 int n,k,m; 11 bool cmp(node p,node q){ 12 return p.y>q.y; 13 } 14 15 struct nn{ 16 int l,r; 17 ll sum; 18 }e[N*4]; 19 void build(int x,int L,int R){ 20 e[x].l=L;e[x].r=R; 21 if(L==R){ 22 e[x].sum=0;return ; 23 } 24 int mid=(L+R)>>1; 25 build(2*x,L,mid); 26 build(2*x+1,mid+1,R); 27 e[x].sum=e[x*2].sum+e[2*x+1].sum; 28 } 29 void update(int v,int x){ 30 if(e[x].l==e[x].r){ 31 e[x].sum++;return ; 32 } 33 int mid=(e[x].l+e[x].r)>>1; 34 if(v<=mid) update(v,2*x); 35 else update(v,2*x+1); 36 e[x].sum=e[x*2].sum+e[2*x+1].sum; 37 } 38 39 int query(int v,int x){ 40 if(e[x].l==e[x].r){ 41 return e[x].l; 42 } 43 if(e[2*x].sum>=v) query(v,2*x); 44 else query(v-e[x*2].sum,2*x+1); 45 } 46 int main(){ 47 while(scanf("%d%d%d",&n,&k,&m)!=EOF){ 48 ll x; 49 build(1,1,n); 50 for(int i=1;i<=n;i++){ 51 scanf("%lld",&x);s[i]=s[i-1]+x; 52 } 53 for(int i=1;i<=m;i++){ 54 scanf("%d%d",&a[i].x,&a[i].y); 55 } 56 sort(a+1,a+1+m,cmp); 57 for(int i=1;i<=k-1;i++){ 58 update(a[i].x,1); 59 } 60 ll Max=0; 61 for(int i=k;i<=m;i++){ 62 update(a[i].x,1); 63 // cout<<e[1].sum<<endl; 64 int xx=query(k,1); 65 //cout<<xx<<" "<<a[i].y<<endl; 66 if(xx<=a[i].y){ 67 Max=max(Max,s[a[i].y]-s[xx-1]); 68 } 69 } 70 cout<<Max<<endl; 71 } 72 return 0; 73 }
时间: 2024-11-29 08:30:47