题面

CF1389F Bicolored Segments

给 \(n\) 条线段 \([l_i,r_i]\),每条有个颜色 \(t_i\in\{0,1\}\),求最多选出多少条线段,使没有不同颜色的线段相交。

数据范围:\(1\le n\le 2\cdot 10^5\),\(1\le l_i\le r_i\le 10^9\)。


蒟蒻语

昨天蒟蒻打 CF,发挥得不错,迷惑回橙。但是蒟蒻没做出这题,赛后想了好久感觉这题很奇妙,于是蒻蒻地来写篇题解。


蒟蒻解一

线段树维护 dp。

先将每条线段 \(l_i,r_i\) 离散化,坐标范围为 \([0,cnt]\)。

设 \(f(i,j,k)\) 表示看了 \([0,i]\),\([j+1,i]\) 的线段颜色都为 \(k\) 的最多线段数。

\[j<i:f(i,j,k)=f(i-1,j,k)+\sum_{x=1}^{n}[l_x>j][r_x=i]
\]
\[f(i,i,k)=\max[\max_{j=0}^{i-1}f(i,j,!k),\max_{j=0}^{i-1}f(i,j,k)]
\]

那么答案是 \(\max_{j=0}^{cnt}f(cnt,j,0/1)\)。

设 \(ca_i\) 这个 vector 存放 \(r_x=i\) 的 \(x\)。

所以可以用一个线段树代替 \(j\) 维,把 \(i\) 维滚掉,实现上述dp。

时间复杂度 \(\Theta(n\log n)\)。

代码

#include <bits/stdc++.h>
using namespace std; //Start
typedef long long ll;
typedef double db;
#define mp(a,b) make_pair(a,b)
#define x first
#define y second
#define be(a) a.begin()
#define en(a) a.end()
#define sz(a) int((a).size())
#define pb(a) push_back(a)
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f; //Data
const int N=2e5,M=(N<<1)+1;
int n,l[N],r[N],t[N],cnt,b[M],ans;
vector<int> ca[M]; //Segmenttree
const int T=M<<2;
#define lk k<<1
#define rk k<<1|1
struct Segmenttree{ //线段树,下标为坐标,维护区间加、全局最大值
int mx[T],mk[T];
void pushup(int k){mx[k]=max(mx[lk],mx[rk]);}
void pm(int k,int v){mk[k]+=v,mx[k]+=v;}
void pushdown(int k){if(mk[k]) pm(lk,mk[k]),pm(rk,mk[k]),mk[k]=0;}
void fix(int x,int y,int v,int k,int l,int r){
if(x<=l&&r<=y) return pm(k,v);
pushdown(k);
int mid=(l+r)>>1;
if(mid>=x) fix(x,y,v,lk,l,mid);
if(mid<y) fix(x,y,v,rk,mid+1,r);
pushup(k);
}
int Mx(){return mx[1];}
void Print(int k,int l,int r){
if(l==r){cout<<mx[k]<<' ';return;}
pushdown(k);
int mid=(l+r)>>1;
Print(lk,l,mid),Print(rk,mid+1,r);
}
}g[2]; //Main
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
for(int i=0;i<n;i++){
cin>>l[i]>>r[i]>>t[i],--t[i];
b[cnt++]=l[i],b[cnt++]=r[i];
}
b[cnt++]=0,sort(b,b+cnt),cnt=unique(b,b+cnt)-b;
for(int i=0;i<n;i++){
l[i]=lower_bound(b,b+cnt,l[i])-b;
r[i]=lower_bound(b,b+cnt,r[i])-b;
ca[r[i]].pb(i);
}
for(int i=1;i<cnt;i++){
for(int x:ca[i]) g[t[x]].fix(0,l[x]-1,1,1,0,cnt);
g[0].fix(i,i,g[1].Mx(),1,0,cnt),g[1].fix(i,i,g[0].Mx(),1,0,cnt);//这么写也是可以的
}
cout<<max(g[0].Mx(),g[1].Mx())<<'\n';
return 0;
}

蒟蒻解二

萌新初学 OI 的时候,有一个贪心问题:求最多线段互不相交。做法是右端点再左端点双关键字排序,然后贪心取舍一下。

这题可以同样地骚操作:

初始化答案为 \(n\)。用两个 multiset 记录两种颜色分别选了哪些线段。

顺序枚举排序了的线段,如果没有选了的线段与当前线段异色并重合,那么蒟蒻们可以很开心地选上这条线段。

否则把右端点在当前线段左端点右边并且最近的异色线段从 multiset 中删除,不往 multiset 中加入当前线段,把答案 \(-1\),表示一个对抗抵消的过程。

比如加了一条 \(0\) 线段,然后再加一条 \(1\) 线段与它抵消。这时如果来 \(2\) 条 \(1\) 线段,相当于选了 \(3\) 条 \(1\) 线段;如果来 \(2\) 条 \(0\) 线段,相当于选了 \(3\) 条 \(0\) 线段。

这种思想类似求序列众数时的对抗抵消选举和模拟网络流反悔推流。

时间复杂度 \(\Theta(n\log n)\)。

代码

#include <bits/stdc++.h>
using namespace std; //Start
typedef long long ll;
typedef double db;
#define mp(a,b) make_pair(a,b)
#define x first
#define y second
#define be(a) a.begin()
#define en(a) a.end()
#define sz(a) int((a).size())
#define pb(a) push_back(a)
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f; //Data
const int N=2e5;
int n,ans;
struct S{int l,r,t;}a[N];
multiset<int> g[2]; //Main
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n,ans=n;
for(int i=0;i<n;i++)
cin>>a[i].l>>a[i].r>>a[i].t,--a[i].t;
sort(a,a+n,[&](const S p,const S q){return p.r==q.r?p.l<q.l:p.r<q.r;});
for(int i=0;i<n;i++)
if(g[!a[i].t].lower_bound(a[i].l)==en(g[!a[i].t])) g[a[i].t].insert(a[i].r);
else ans--,g[!a[i].t].erase(g[!a[i].t].lower_bound(a[i].l));
cout<<ans<<'\n';
return 0;
}

祝大家学习愉快!

题解-CF1389F Bicolored Segments的更多相关文章

  1. Codeforces Educational Round 92 赛后解题报告(A-G)

    Codeforces Educational Round 92 赛后解题报告 惨 huayucaiji 惨 A. LCM Problem 赛前:A题嘛,总归简单的咯 赛后:A题这种**题居然想了20m ...

  2. CodeForces 430A Points and Segments (easy)(构造)题解

    题意:之前愣是没看懂题意...就是给你n个点的坐标xi,然后还规定了Li,Ri,要求给每个点染色,每一组L,R内的点红色和黑色的个数不能相差大于1个,问你能不能染成功,不能输出-1,能就按照输入的顺序 ...

  3. LeetCode题解之Number of Segments in a String

    1.题目描述 2.题目分析 找到字符串中的空格即可 3.代码 int countSegments(string s) { ){ ; } vector<string> v; ; i < ...

  4. PAT甲题题解-1104. Sum of Number Segments (20)-(水题)

    #include <iostream> #include <cstdio> #include <algorithm> #include <string.h&g ...

  5. POJ3304:Segments——题解

    http://poj.org/problem?id=3304 题目大意:给n条线段,求是否存在一条直线,将所有线段投影到上面,使得所有投影至少交于一点. ——————————————————————— ...

  6. [CF1167D]Bicolored RBS题解

    模拟两个颜色的扩号层数,贪心,如果是左括号,哪边的层数浅就放那边:如果是右括号,哪边的层数深就放那边. 至于层数的维护,两个int就做掉了 放个代码: #include <cstdio> ...

  7. [CF846C]Four Segments题解

    我们暴力枚举一下\(delim_{1}\) 然后对于每个\(delim_{1}\),O(n)扫一遍+前缀和求出最大\(delim_{0}\)和\(delim_{2}\),然后记录一下它们的位置就行啦 ...

  8. 【题解】CF1426D Non-zero Segments

    题目戳我 \(\text{Solution:}\) 若\([l,r]\)子段和是\(0,\)则\(sum[r]=sum[l-1].\) 于是我们可以考虑维护当前哪一个前缀和出现过.对于区间\([l,r ...

  9. Codeforces Round #337 (Div. 2) D. Vika and Segments 线段树 矩阵面积并

    D. Vika and Segments     Vika has an infinite sheet of squared paper. Initially all squares are whit ...

随机推荐

  1. 《GNU_Makefile》第4章——makefile规则

    规则明确在什么情况下,使用什么方法,重构文件,该文件称为目标. make的唯一目的是重构终极目标.终极目标默认是第一个目标. 1. 2.规则语法 TARGETS : PREREQUISITES COM ...

  2. mysql_用命令行备份数据库

    MySQL数据库使用命令行备份|MySQL数据库备份命令 例如: 数据库地址:127.0.0.1 数据库用户名:root 数据库密码:pass 数据库名称:myweb 备份数据库到D盘跟目录 mysq ...

  3. DevOps,你真的了解吗?

    与大数据和PRISM(NSA的监控项目之一),DevOps(开发运维)如今是科技人士挂在嘴边的热词,但遗憾的是,类似圣经,每个人都引用DevOps的只言片语,但真正理解并能执行的人极少.根据CA的一项 ...

  4. Springboot 完整搭建快速入门,必看!

    前言 手把手教你Springboot微服务项目搭建快速入门,通过本文学习Springboot的搭建快速入门,掌握微服务大致的配置服务,后续将会继续将核心组件引入到项目中,欢迎关注,点赞,转发. Spr ...

  5. Python 调用接口添加头信息

    import requests,jsonurl = 'http://47.108.115.193:9000/tb-store/store/getWechatAppHome'header={" ...

  6. web安全原理分析-SQL注入漏洞全解

    简介 靶场:榆林学院信息安全协会--入侵榆大实验靶场 数字型注入 1 字符型注入 1 布尔注入 1.布尔注入简介 mysql bool注入是盲注的一种.与报错注入不同,bool注入没有任何报错信息输出 ...

  7. 计算思维(美国CMU周以真教授)

    博主注:GIScience会议是国际上最为著名的地理信息系统领域的国际会议,自2000年起,每两年举办一次,GIScience 2008会议邀请了美国卡内基-梅隆大学(CMU)计算机系华裔教授周以真博 ...

  8. python-网络安全编程第五天(爬虫模块BeautifulSoup)

    前言 昨晚学的有点晚 睡得很晚了,今天早上10点多起来吃完饭看了会电视剧就瞌睡了一直睡到12.50多起来洗漱给我弟去开家长会 开到快4点多才回家.耽搁了不少学习时间,现在就把今天所学的内容总结下吧. ...

  9. unctf2020 部分简单题题解

    unctf2020 水一波简单题..菜狗前来报道..大佬轻喷..如果有时间做题就好了呜呜呜 misc 1.baba_is_you 题目告诉我们,了解png文件格式. 下载得到一张png格式的图片. 用 ...

  10. 金九银十想面BAT?那这些JDK 动态代理的面试点你一定要知道

    一.什么是代理 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理. 代理模式UM ...