题面

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. C/C++中内存对齐问题的一些理解(转)

    内存对齐指令 一般来说,内存对齐过程对coding者来说是透明的,是由编译器控制完成的 如对内存对齐有明确要求,可用#pragma pack(n)指定,以n和结构体中最长数据成员长度中较小者为有效值 ...

  2. 用GitHub Pages搭建博客(六)

    本篇介绍GitHub Pages网站加速 在上一篇提到如何对GitHub Pages配置自定义域名.其实,不论GitHub Pages的默认域名还是自定义域名,都使用了GitHub的CDN进行加速,虽 ...

  3. 源码分析:升级版的读写锁 StampedLock

    简介 StampedLock 是JDK1.8 开始提供的一种锁, 是对之前介绍的读写锁 ReentrantReadWriteLock 的功能增强.StampedLock 有三种模式:Writing(读 ...

  4. 关于多线程--网络编程 -- 注解反射的一点笔记(JAVA篇)

    一 . 线程 java开启一个线程的方法(三种) 方法一:继承Thread类并New一个线程对象 步骤: 1):定义一个类A继承于Java.lang.Thread类. class TestThread ...

  5. Redis分布式锁的正确使用与实现原理

    模拟一个电商里面下单减库存的场景. 1.首先在redis里加入商品库存数量. 2.新建一个Spring Boot项目,在pom里面引入相关的依赖. <dependency> <gro ...

  6. PID算法终于弄明白原理了,原来就这么简单

    看起来PID高大尚,实则我们都是被他的外表所震撼住了.先被别人唬住,后被公式唬住,由于大多数人高数一点都不会或者遗忘,所以再一看公式,简直吓死.了解了很浅的原理后,结果公式看不懂,不懂含义,所以最终没 ...

  7. CSS 常用列表样式

    CSS 常用列表样式 CSS没学扎实,复习记录一下.下面是一些常用的属性 list-style-image 指定一个图片作为列表项的标记 默认值none,可设置为图片的url list-style-i ...

  8. 我要进大厂之大数据MapReduce知识点(1)

    01 我们一起学大数据 老刘今天分享的是大数据Hadoop框架中的分布式计算MapReduce模块,MapReduce知识点有很多,大家需要耐心看,用心记,这次先分享出MapReduce的第一部分.老 ...

  9. metasploit数据库使用学习

    metasploit为了方便,自动将当前工作区的内容放入数据库 首先就是工作区 -a 增加工作区,-d删除工作区 不同工作区的内容会分开储存到数据库 default工作区 test工作区 db_imp ...

  10. Mac系统应该用什么软件进行清理?

    作为一枚资深的Windows系统使用者,小编刚刚转向Mac系统的怀抱时,各种不适应,Windows系统中普遍使用的360清理软件目前暂时没有Mac版本的,这就让小编很是头疼了,大家的Mac都是用的什么 ...