HDU 5700 区间交(树状数组+二分+思维)好题。。

区间交

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1424    Accepted Submission(s): 543


 

Problem Description

小A有一个含有n个非负整数的数列与m个区间。每个区间可以表示为li,ri

它想选择其中k个区间, 使得这些区间的交的那些位置所对应的数的和最大。

例如样例中,选择[2,5]与[4,5]两个区间就可以啦。

 

Input

多组测试数据

第一行三个数n,k,m(1≤n≤100000,1≤km≤100000)。

接下来一行n个数ai,表示lyk的数列(0≤ai≤109)。

接下来m行,每行两个数li,ri,表示每个区间(1≤lirin)。

 

 

Output

一行表示答案

 

Sample Input

 

5 2 3 1 2 3 4 6 4 5 2 5 1 4

 

Sample Output

 

10

 

Source

2016"百度之星" - 初赛(Astar Round2B)

 

Recommend

wange2014   |   We have carefully selected several similar problems for you:  6331 6330 6329 6328 6327 

 

Statistic | Submit | Discuss | Note

#include<iostream>
#include<algorithm>
#include<string>
#include<map>//int dx[4]={0,0,-1,1};int dy[4]={-1,1,0,0};
#include<set>//int gcd(int a,int b){return b?gcd(b,a%b):a;}
#include<vector>
#include<cmath>
#include<stack>
#include<string.h>
#include<stdlib.h>
#include<cstdio>
#define mod 1e9+7
#define ll long long
#define maxn 100005
#define MAX 1000000000
#define ms memset
using namespace std;

int n,k,m,x;
ll seq[maxn];
int tree[maxn];///树状数组
/*
中文题目,题意不解释

首先我们需要数组的前缀和,这个就不用树状数组来维护了,
因为结果和查询的数量没有关系的。
题目给定了m个区间要求选k个,最终结果是所有区间重叠的部分。

又是这种组合优化问题,
m个中选择k个最大化答案。
直接枚举超时没话说。(C(m,k))

不妨观察答案区间的性质,首先如果存在一个答案区间,
那么其左边界一定是区间的一个左边界。
不妨遍历所有区间的左边界,对每个遍历到的区间,
用线段树维护其过程中区间重叠的最大次数,
因为观察加上自己想也可以知道这个序列应该是递减的,
二分查找满足大于等于k的最右边界(贪心)。
那么每次遍历时就可以维护一个最大值,即答案。
用二分得来的右界和遍历到的左边界构造出最大答案参与比较即可。

*/

struct node
{
    int l,r;
};
node q[maxn];

bool cmp(node x,node y)
{
    if(x.l==y.l) return x.r<y.r;
    return x.l<y.l;
}

int lowbit(int x) {return x&(-x);}

ll sum(int x) { ll res=0;for(;x>0;res+=tree[x],x-=lowbit(x)); return res;}

void add(int x,int d) { for( ; x<=n ; tree[x]+=d , x+=lowbit(x) ); }

int main( )
{
    while(scanf("%d%d%d",&n,&k,&m)!=EOF)
    {
        memset(tree,0,sizeof(tree));

        for(int i=1;i<=n;i++) { scanf("%d",&x) ; seq[i]=seq[i-1]+x; }
        for(int i=0;i<m;i++) scanf("%d%d",&q[i].l,&q[i].r);
        sort(q,q+m,cmp);

        ll ans=0;

        for(int i=0;i<m;i++)
        {
            add(q[i].l,1);
            add(q[i].r+1,-1);
            int l=q[i].l,r=q[i].r;
            int pos=-1;
           // for(int i=l;i<=r;i++) cout<<sum(i)<<" ";puts("");
            while(r>=l)
            {
                int mid=(l+r)>>1;
                if(sum(mid)>=k)
                {
                    pos=mid;
                    l=mid+1;///取其最右的端点边界
                }
                else r=mid-1;
            }
            if(pos==-1) continue;
            else ans=max(ans,seq[pos]-seq[q[i].l-1]);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37451344/article/details/81293594