51Nod-1672 区间交 (贪心+线段树)

1672 区间交 

基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题

 收藏

 关注

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

它想选择其中k个区间, 使得这些区间的交的那些位置所对应的数的和最大。(是指k个区间共同的交,即每个区间都包含这一段,具体可以参照样例)

 

在样例中,5个位置对应的值分别为1,2,3,4,6,那么选择[2,5]与[4,5]两个区间的区间交为[4,5],它的值的和为10。

Input

第一行三个数n,k,m(1<=n<=100000,1<=k<=m<=100000)。
接下来一行n个数ai,表示小A的数列(0<=ai<=10^9)。
接下来m行,每行两个数li,ri,表示每个区间(1<=li<=ri<=n)。

Output

一行表示答案

Input示例

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

Output示例

10

题解:按照区间左端点从小到大排序,从左至右枚举区间,线段树维护右端点,根据贪心思想,一定是找右端点第k大的。

#include<bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define x first
#define y second
#define rep(i,a,b) for(int i=a;i<b;++i)
#define per(i,a,b) for(int i=a-1;i>=b;--i)
#define fuck(x) cout<<'['<<#x<<' '<<(x)<<']'
#define add(x,y) x=((x)+(y)>=mod)?(x)+(y)-mod:(x)+(y)
#define sub(x,y) x=((x)-(y)<0)?(x)-(y)+mod:(x)-(y)
#define eps 1e-10
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> VI;
typedef pair<int, int> PII;

const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fll;
const int MX = 1e5 + 5;
const int mod = 1e9 + 9;

int a[MX];
ll pre[MX];
struct Line {
    int l, r;
    bool operator<(const Line& _A)const {
        if(l != _A.l) return l < _A.l;
        return r < _A.r;
    }
} b[MX];
int mx[MX << 2];
void PushUP(int rt) {
    mx[rt] = mx[rt << 1] + mx[rt << 1 | 1];
}
void update(int p, int l, int r, int rt) {
    if(l == r) {
        mx[rt]++;
        return;
    }
    int m = (l + r) >> 1;
    if(p <= m) update(p, lson);
    else update(p, rson);
    PushUP(rt);
}
int query(int k, int l, int r, int rt) {
    if(l == r) return l;
    int m = (l + r) >> 1;
    if(mx[rt << 1 | 1] >= k) return query(k, rson);
    return query(k - mx[rt << 1 | 1], lson);
}

int main() {
#ifdef local
    freopen("in.txt", "r", stdin);
#endif // local
    int n, k, m; cin >> n >> k >> m;
    rep(i, 1, n + 1) cin >> a[i];
    rep(i, 1, n + 1) pre[i] = pre[i - 1] + a[i];
    rep(i, 1, m + 1) cin >> b[i].l >> b[i].r;
    sort(b + 1, b + m + 1);
    ll ans = 0;
    rep(i, 1, k) update(b[i].r, 1, n, 1);
    rep(i, k, m + 1) {
        update(b[i].r, 1, n, 1);
        int l = b[i].l, r = query(k, 1, n, 1);
        if(l <= r) ans = max(ans, pre[r] - pre[l - 1]);
    }
    cout << ans << endl;
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值