hdu-5700 区间交(二分+树状数组)

题目链接:

区间交

Problem Description
 

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

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

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

 

Input
 

多组测试数据

第一行三个数n,k,m(1n100000,1km100000)。

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

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

 

Output
 

一行表示答案

 

 

Sample Input
 
5 2 3
1 2 3 4 6
4 5
2 5
1 4
Sample Output
 
10

题意:


思路:

求相交区间和的最大值,首先是树状数组sum可以求log(n)求区间和,在找区间的时候枚举左端点,二分右端点,先把区间按左端点排序,然后一边更新一边询问,由于按左端点排序,所以左端点可以作为相交区间的左端点,二分右端点时询问这个点是否被大于等于k次覆盖,找到右端点最大的那个点,此时对应的区间就是这个左端点能得到的最大的区间,枚举完左端点就可以找到最大值了;
复杂度好像是mlog(n)log(n);


AC代码:

#include <bits/stdc++.h>
/*
#include <iostream>
#include <queue>
#include <cmath>
#include <map>
#include <cstring>
#include <algorithm>
#include <cstdio>
*/
using namespace std;
#define Riep(n) for(int i=1;i<=n;i++)
#define Riop(n) for(int i=0;i<n;i++)
#define Rjep(n) for(int j=1;j<=n;j++)
#define Rjop(n) for(int j=0;j<n;j++)
#define mst(ss,b) memset(ss,b,sizeof(ss));
typedef long long LL;
const LL mod=1e9+7;
const double PI=acos(-1.0);
const int inf=0x3f3f3f3f;
const int N=1e5+4;
int n,k,m;
LL a[N];
LL sum[N];
int num[N];
struct node
{
    int l,r;
}po[N];
int cmp(node x,node y)
{
    if(x.l==y.l)x.r>y.r;
    return x.l<y.l;
}
int lowbit(int x)
{
    return x&(-x);
}
void update(int x,LL y)
{
    while(x<=n)
    {
        sum[x]+=y;
        x+=lowbit(x);
    }
}
LL query(int pos)
{
    LL ans=0;
    while(pos>0)
    {
        ans+=sum[pos];
        pos-=lowbit(pos);
    }
    return ans;
}
void update1(int x,int flag)
{
    while(x<=n)
    {
        num[x]+=flag;
        x+=lowbit(x);
    }
}
int query1(int x)
{
    int ans=0;
    while(x>0)
    {
            ans+=num[x];
            x-=lowbit(x);
    }
    return ans;
}
int check(int x)
{
    if(query1(x)>=k)return 1;
    return 0;
}
int main()
{
        while(scanf("%d%d%d",&n,&k,&m)!=EOF)
        {
            LL ans=0;
            mst(num,0);
            mst(sum,0);
            Riep(n)scanf("%lld",&a[i]),update(i,a[i]);
            Riep(m)scanf("%d%d",&po[i].l,&po[i].r);
            sort(po+1,po+m+1,cmp);
            for(int i=1;i<=m;i++)
            {
                update1(po[i].l,1);
                update1(po[i].r+1,-1);
                int L=po[i].l,R=po[i].r;
                while(L<=R)
                {
                    int mid=(L+R)>>1;
                    if(check(mid))L=mid+1;
                    else R=mid-1;
                }
                LL fx=query(L-1),fy;
                if(po[i].l>1)fy=query(po[i].l-1);
                else fy=0;
                ans=max(ans,fx-fy);
            }
            printf("%lld\n",ans);
        }
    return 0;
}

 

posted @ 2016-05-25 13:07  LittlePointer  阅读(982)  评论(2编辑  收藏  举报