【51nod1672】区间交

题目大意:给定一个长度为 N 的序列,以及 M 个区间,现从中选出 K 个区间,使得这些区间的交集区间的点权和最大,求最大值是多少。

题解:
发现直接选 K 个区间不可做,考虑从答案入手。设答案区间为 [l,r],进行枚举答案区间的左端点。当前枚举到的左端点设为 L,那么能够以 L 作为左端点的区间一定满足左端点不超过 L,且右端点大于等于 L。考虑若有超过 K 个区间符合要求,那么肯定是选取较大的 K 个区间的答案更优,因此只需求出符合条件的区间右端点的第 K 大值,并更新答案即可。再考虑 L 之间的转移带来的变化,枚举到 L 时,应该将符合要求的答案更新;同样,统计完 L 的贡献之后,应该将对于 L+1 不符合情况的解删去。需要维护一个支持插入删除和求第 K 大的数据结构,显然权值线段树符合要求。

代码如下

#include <bits/stdc++.h>
#define pb push_back
using namespace std;
const int maxn=1e5+10;
typedef long long LL;

int n,m,K,sz[maxn<<2];
LL a[maxn],sum[maxn],ans;
vector<int> st[maxn],ed[maxn];
void insert(int o,int l,int r,int pos,int val){
    if(l==r){sz[o]+=val;return;}
    int mid=l+r>>1;
    if(pos<=mid)insert(o<<1,l,mid,pos,val);
    else insert(o<<1|1,mid+1,r,pos,val);
    sz[o]=sz[o<<1]+sz[o<<1|1];
}
int kth(int o,int l,int r,int k){
    if(l==r)return l;
    int mid=l+r>>1;
    if(sz[o<<1|1]>=k)return kth(o<<1|1,mid+1,r,k);
    else return kth(o<<1,l,mid,k-sz[o<<1|1]);
}

void read_and_parse(){
    scanf("%d%d%d",&n,&K,&m);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        sum[i]=sum[i-1]+a[i];
    }
    for(int i=1;i<=m;i++){
        int l,r;
        scanf("%d%d",&l,&r);
        st[l].pb(r),ed[r].pb(r);
    }
}
void solve(){
    for(int i=1;i<=n;i++){
        for(auto r:st[i])insert(1,1,n,r,1);
        if(sz[1]>=K){
            int pos=kth(1,1,n,K);
            ans=max(ans,sum[pos]-sum[i-1]);
        }
        for(auto r:ed[i])insert(1,1,n,r,-1);
    }
    printf("%lld\n",ans);
}
int main(){
    read_and_parse();
    solve();
    return 0;
} 

原文地址:https://www.cnblogs.com/wzj-xhjbk/p/11074078.html

时间: 2024-08-30 07:38:57

【51nod1672】区间交的相关文章

HDU 5700 区间交(线段树)

题目链接 区间交 1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define rep(i, a, b) for (int i(a); i <= (b); ++i) 6 #define dec(i, a, b) for (int i(a); i >= (b); --i) 7 8 #define lson i << 1, L, mid 9 #define rson i << 1 | 1, mid

HDU 5700——区间交——————【线段树+枚举】

区间交 Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 567    Accepted Submission(s): 279 Problem Description 小A有一个含有n个非负整数的数列与m个区间.每个区间可以表示为li,ri. 它想选择其中k个区间, 使得这些区间的交的那些位置所对应的数的和最大. 例如样例中,选择[2,5]

hdu 5700区间交(线段树)

区间交 Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 849    Accepted Submission(s): 377 Problem Description 小A有一个含有n个非负整数的数列与m个区间.每个区间可以表示为li,ri. 它想选择其中k个区间, 使得这些区间的交的那些位置所对应的数的和最大. 例如样例中,选择[2,5]

区间交

Problem Description 小A有一个含有nn个非负整数的数列与mm个区间.每个区间可以表示为l?i??,r?i??. 它想选择其中k个区间, 使得这些区间的交的那些位置所对应的数的和最大. 例如样例中,选择[2,5]与[4,5]两个区间就可以啦. Input 多组测试数据 第一行三个数n,k,m(1≤n≤100000,1≤k≤m≤100000). 接下来一行n个数a?i??,表示lyk的数列(0≤a?i??≤10?9??). 接下来m行,每行两个数l?i??,r?i,表示每个区间(

HDU 5700 区间交 线段树暴力

枚举左端点,然后在线段树内,更新所有左边界小于当前点的区间的右端点,然后查线段树二分查第k大就好 #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; const int N = 100005; LL a[N]; struct Node{ int l,r; bool operator<(const Node &

poj 3881 区间交判断

水题,直接贴代码. //poj 3881 //sep9 #include <iostream> using namespace std; const int maxN=10024; int n,m; int a[maxN],b[maxN]; bool judge(int x,int y,int i) { if(b[i]<=x||y<=a[i]) return false; return true; } int main() { while(scanf("%d%d"

「6月雅礼集训 2017 Day4」qyh(bzoj2687 交与并)

原题传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2687 [题目大意] 给出若干区间,求一个区间的大于等于2的子集,使得 |区间并| 和 |区间交| 的乘积最大. $1\leq n, L_i, R_i \leq 10^6$ [题解] 把区间去掉包含情况,然后进行排序,变成$L_i$和$R_i$都递增的数列. 然后容易发现取得区间一定是连续的一段. 然后我们推一推决策单调性,我把考试的时候推的写在代码里了 然后直接单调队列优化即可. 然后

51NOD 1962 区间计数 单调栈+二分 / 线段树+扫描线

 区间计数 基准时间限制:1.5 秒 空间限制:262144 KB 分值: 80 两个数列 {An} , {Bn} ,请求出Ans, Ans定义如下: Ans:=Σni=1Σnj=i[max{Ai,Ai+1,...,Aj}=max{Bi,Bi+1,...,Bj}] 注:[ ]内表达式为真,则为1,否则为0. 1≤N≤3.5×1051≤Ai,Bi≤N 样例解释: 7个区间分别为:(1,4),(1,5),(2,4),(2,5),(3,3),(3,5),(4,5) Input 第一行一个整数N 第二行

2016年浙江财经大学信工学院程序设计竞赛题解

代码为本人出于爱好 验题时所写,如有错误,敬请指出. 题面$pdf$为本人排版,不到之处,还请海涵.  联系方式$QQ$:$774388357$  浙江财经大学 $14$软件工程 周甄陶 正赛题面:https://pan.baidu.com/s/1jIQASxo 热身赛题面:https://pan.baidu.com/s/1mi4mjMg 热身赛$pdf$密码:IbcS3jJkkOsxiMCYfF6v 弱校现场赛$Rank$:https://pan.baidu.com/s/1kVBFGMV 热身