当前位置: 首页 > news >正文

守卫-贪心,线段处理

P3634 守卫-贪心


P3634 守卫
这个线段处理值的学习

题意

给定区间及权值 \(0/1\),还有总共 \(1\) 的个数 \(k\) ,表示区间内是否有 \(1\) ,问一定为 \(1\) 的点有那些。

思路

很容易发现:

  1. \(0\) 的区间一定没有一。
  2. 去掉 \(0\) 之后长度刚好为 \(k\) 则一定有 \(1\)
  3. 值为 1 的区间长度恰好为 \(1\) 的时候,一定满足条件。
  4. 如果存在区间包含关系,保留小的区间。--小的区间外都可以为 \(0\)

考虑剩下的区间,容易发现如果在区间相交的地方存在 1 ,可以减少剩余可能存在 1 的区间数量。因为如果权值为 1 的区间内有 1 ,那剩余区间就是可能有 1 ,不符合要求。可以用来判断无解。

考虑 1 最少的情况,因为此时总和最小,如果不选某个点导致总和超过 \(k\) ,则必须选这个点,因为无论如何构造都不会有方式让总和小于 \(k\)

细节

  1. 1 最少的情况用线段覆盖来求。
  2. 保留的线段权值都为 1 ,且删去权值为 0 的线段。
  3. 判断是否无解要知道在这个点前面作最优解和这个点后面作最优解,所以对得到的最小情况要做一次前缀和和后缀和。

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;
constexpr int maxn = 1e5+10;
constexpr int INF = 0x3f3f3f3f3f3f3f3f;typedef struct line
{int l,r;bool operator<(const line &o)const // l为第一关键字{return l!=o.l ? l<o.l : r<o.r;}
}line;int n,k,m;// 长,个数,区间数
int d[maxn];// 差分数组, 标记0的线段覆盖
int idx,cnt;// 线段数量,可能为1的点
line lin[maxn];// 线段-1
int pre[maxn],suf[maxn];// i左边可能为1的点的编号(cnt)
int sti[maxn];// 临时存储剩余的线段下标
int pre_cnt[maxn],suf_cnt[maxn];// 到某个线段最少要选取的点数(前后缀和)
int cov[maxn]; // cnt转坐标signed main()
{#ifndef ONLINE_JUDGEfreopen("cjdl.in","r",stdin);freopen("cjdl.out","w",stdout);#endif // ONLINE_JUDGEscanf("%lld%lld%lld",&n,&k,&m);for(int i=1,a,b,c ;i<=m;++i){scanf("%lld%lld%lld",&a,&b,&c);if(c==0){++d[a];// 差分标记--d[b+1];}else{++idx;lin[idx]={a,b};}}for(int i=1;i<=n;++i){// 还原差分,找剩下1的点d[i+1]+=d[i];if(!d[i]){pre[i]=suf[i]=++cnt;cov[cnt]=i;}}if (k == cnt)// 如果刚好满足,必须要判!{for (int i = 1; i <= cnt; i++){printf("%lld\n", cov[i]);}return 0;}for(int i=1;i<=n;++i)// 映射,似乎可以不用{if(!pre[i]){pre[i]=pre[i-1];}}for(int i=n;i>=1;--i){if(!suf[i]){suf[i]=suf[i+1];}}for(int i=1;i<=idx;++i){lin[i].l=suf[lin[i].l];// 跳过0的点lin[i].r=pre[lin[i].r];}sort(lin+1,lin+1+idx);// 现在排序for(int i=1;i<=idx;++i){if(lin[i].l>lin[i].r){continue;}while(sti[0] && lin[sti[sti[0]]].r>=lin[i].r)// 删除包含小线段的线段{--sti[0];}sti[++sti[0]]=i;}idx=sti[0];for(int i=1;i<=idx;++i){lin[i]=lin[sti[i]];// 挑完的线段}int rr=0;// 前缀最少要选取的点数for(int i=1;i<=idx;++i){if(lin[i].l>rr){pre_cnt[i]=pre_cnt[i-1]+1;rr=lin[i].r;}else{pre_cnt[i]=pre_cnt[i-1];}}int ll=INF;// 后缀for(int i=idx;i>=1;--i){if(lin[i].r<ll){suf_cnt[i]=suf_cnt[i+1]+1;ll=lin[i].l;}else{suf_cnt[i]=suf_cnt[i+1];}}bool flag=0;for(int i=1;i<=idx;++i){if(lin[i].l==lin[i].r)// 一个点必须要{flag=1;printf("%lld\n",cov[lin[i].l]);continue;}if(pre_cnt[i] != pre_cnt[i-1]+1) continue;// 不是有影响的线段右端点int pos=idx+1;int l=i+1,r=idx;// 二分找下一个线段(左端点刚好大) 可以用双指针更快while(l<=r){int mid=l+((r-l)>>1);if(lin[mid].l>lin[i].r-1){pos=mid;r=mid-1;}else{l=mid+1;}}if(pre_cnt[i]+suf_cnt[pos]>k)// 不选这个点无解{flag=1;printf("%lld\n",cov[lin[i].r]);}}if(!flag)// 没有选一个点{printf("-1\n");}return 0;
}
http://www.jsqmd.com/news/38060/

相关文章:

  • 2025年中央空调生产商排行榜单
  • 2025年口碑好的不锈钢衣柜优质厂家推荐榜单
  • Mysql常问面试题 - 教程
  • 2025年风管机实力厂家哪家权威
  • 2025年电脑维修常见故障渠道怎么选择
  • 2025冷库聚氨酯保温批发厂家推荐榜
  • 2025年质量好的恩施装修半包本地口碑榜
  • 深入解析:【鸿蒙进阶-7】鸿蒙与web混合开发
  • 深入解析:牛客周赛 Round 111
  • 2025年质量好的开天品牌口碑榜
  • Python3 正则表达式
  • 2025年11月水飞蓟Q10胶囊推荐:科学护肝能量双效协同方案
  • Python3 OS 文件/目录方法详解
  • 2025三轮车伸缩雨棚企业推荐榜单
  • 2025年11月EGUOO男士三氨能量推荐:全网口碑验证千万销量同款矩阵
  • 2025年AI营销渠道排行榜
  • revit api创建墙体剖面视图
  • 2025入职背调全方位的推荐排行榜
  • 2025年11月EGUOO男士三氨能量推荐:30片便携装随时补充男士能量
  • 2025年靠谱的高强度铝合金线槽用户好评厂家排行
  • 2025年瑜伽垫供应厂家口碑排行榜
  • 《软件需求十步走》读书笔记2
  • 2025年发光鼠标垫产品口碑排行榜
  • 详细介绍:Home Assistant 米家集成:开启智能家居新体验
  • 2025年小区车棚产品排名
  • 第九周第二天9.2
  • 2025年膜结构工厂排行榜
  • 2025年评价高的国标铝合金线槽行业内口碑厂家排行榜
  • transformers库本地部署大语言模型 - yi
  • 2025年广州旅游大巴出租平台推荐排行榜单