题解-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\) 的最多线段数。
\]
\]
那么答案是 \(\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的更多相关文章
- Codeforces Educational Round 92 赛后解题报告(A-G)
Codeforces Educational Round 92 赛后解题报告 惨 huayucaiji 惨 A. LCM Problem 赛前:A题嘛,总归简单的咯 赛后:A题这种**题居然想了20m ...
- CodeForces 430A Points and Segments (easy)(构造)题解
题意:之前愣是没看懂题意...就是给你n个点的坐标xi,然后还规定了Li,Ri,要求给每个点染色,每一组L,R内的点红色和黑色的个数不能相差大于1个,问你能不能染成功,不能输出-1,能就按照输入的顺序 ...
- LeetCode题解之Number of Segments in a String
1.题目描述 2.题目分析 找到字符串中的空格即可 3.代码 int countSegments(string s) { ){ ; } vector<string> v; ; i < ...
- PAT甲题题解-1104. Sum of Number Segments (20)-(水题)
#include <iostream> #include <cstdio> #include <algorithm> #include <string.h&g ...
- POJ3304:Segments——题解
http://poj.org/problem?id=3304 题目大意:给n条线段,求是否存在一条直线,将所有线段投影到上面,使得所有投影至少交于一点. ——————————————————————— ...
- [CF1167D]Bicolored RBS题解
模拟两个颜色的扩号层数,贪心,如果是左括号,哪边的层数浅就放那边:如果是右括号,哪边的层数深就放那边. 至于层数的维护,两个int就做掉了 放个代码: #include <cstdio> ...
- [CF846C]Four Segments题解
我们暴力枚举一下\(delim_{1}\) 然后对于每个\(delim_{1}\),O(n)扫一遍+前缀和求出最大\(delim_{0}\)和\(delim_{2}\),然后记录一下它们的位置就行啦 ...
- 【题解】CF1426D Non-zero Segments
题目戳我 \(\text{Solution:}\) 若\([l,r]\)子段和是\(0,\)则\(sum[r]=sum[l-1].\) 于是我们可以考虑维护当前哪一个前缀和出现过.对于区间\([l,r ...
- 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 ...
随机推荐
- 用GitHub Pages搭建博客(六)
本篇介绍GitHub Pages网站加速 在上一篇提到如何对GitHub Pages配置自定义域名.其实,不论GitHub Pages的默认域名还是自定义域名,都使用了GitHub的CDN进行加速,虽 ...
- Jmeter 添加 计数器
第一步: 添加 > 配置元件 > 计数器 如下图所示: 第二步: 设置递增值与引用名称 第三步:使用引用名称 第四步:执行脚本,查看结果
- deepin V20 简易入门指南
deepin V20 入坑指南 系统安装 入坑第一步自然是先安装系统了,deepin的安装方式很简单只需要一个U盘即可,在官网下载好安装镜像文件,使用官方的启动盘制作工具,开机时选择从U盘启动即可,安 ...
- (buuctf) - pwn入门部分wp - rip -- pwn1_sctf_2016
[buuctf]pwn入门 pwn学习之路引入 栈溢出引入 test_your_nc [题目链接] 注意到 Ubuntu 18, Linux系统 . nc 靶场 nc node3.buuoj.cn 2 ...
- 关于GoldWave为Vegas制作音频交叉淡化特效的教程分享
在Vegas里对音频交叉淡化的处理,是通过将两段音频交叠.调整交叠部分的音量.选取交叉淡化类型这三步来实现的,许多步骤是在音频轨道拖动音量线来实现的,操作上不够灵敏精细.其实,单就音频的交叉淡化处理, ...
- mysql5.5升级5.7(1)
卸载旧版本mysql 当然要记得备份数据库数据啦 1.查看需要卸载的部分: rpm -qa |grep -i mysql 2.开始卸载: yum remove mysql* 接下来是安装新版mysql ...
- Contest 1428
A 移动次数是 \(\left|x_1-x_2\right|+\left|y_1-y_2\right|\). 如果 \(x_1\not=x_2\) 且 \(y_1\not=y_2\) 说明要换方向,两 ...
- EXCEL发送为只读打开
(1)进入文件夹: C:\Users\xxx\AppData\Roaming\Microsoft\Windows\SendTo (2)新建快捷方式 (3)输入: "C:\Program Fi ...
- VisualStudio 编写汇编代码相关设置
VS编写汇编代码方法 新建空项目,不创建解决方案 项目右键,Build Customizations,选择masm 新建源文件,后缀为.ASM 编写代码 .386 ; Tells MASM to us ...
- poi 1182
食物链 || 带权并查集 0:同类 1:吃 2:被吃 #include <cstdio> using namespace std; const int maxn=5e4+3; int f[ ...