D 洛谷 P3602 Koishi Loves Segments [贪心 树状数组+堆]
题目描述
Koishi喜欢线段。
她的条线段都能表示成数轴上的某个闭区间。Koishi喜欢在把所有线段都放在数轴上,然后数出某些点被多少线段覆盖了。
Flandre看她和线段玩得很起开心,就抛给她一个问题:
数轴上有个点突然兴奋,如果自己被身上覆盖了超过条线段,这个点就会浑身难受然后把Koishi批判一番。
Koishi十分善良,为了不让数轴上的点浑身难受,也为了让自己开心,她想在数轴上放入尽量多的线段。
按照套路,Koishi假装自己并不会做这道题,所以她就来求你帮忙。并承诺如果你解决了问题就给你打一通电话w。
输入输出格式
输入格式:
第一行两个个整数,分别表示插入的线段数和关键点数。
接下来行,每行两个整数,表示线段的端点。
接下来行,每行两个整数,表示有个位于的点突然兴奋,并认为自己身上不得覆盖超过条线段
输出格式:
一个整数,表示最多能放入的线段数
输入输出样例
4 3
1 3
2 4
5 7
6 8
2 5
3 1
6 2
3
说明
对于20%的数据,满足
对于60%的数据,满足
对于80%的数据,满足
对于100%的数据,满足
如果一个点兴奋了两次,那么Koishi应当满足它的*较严苛的要求*(也就是相同时取最小值啦)
请适当使用读入优化
比赛时交了一个网络流60分
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
const int N=,M=1e6,INF=1e9;
inline int read(){
char c=getchar();int x=,f=;
while(c<''||c>''){if(c=='-')f=-; c=getchar();}
while(c>=''&&c<=''){x=x*+c-''; c=getchar();}
return x*f;
}
int n,m,s,t;
struct rec{
int l,r;
}a[N];
struct point{
int p,k;
bool operator <(const point a)const{
if(p==a.p) return k<a.k;
else return p<a.p;
}
}b[N]; struct edge{
int v,c,f,ne;
}e[M<<];
int cnt,h[N];
inline void ins(int u,int v,int c){
cnt++;
e[cnt].v=v;e[cnt].c=c;e[cnt].f=;e[cnt].ne=h[u];h[u]=cnt;
cnt++;
e[cnt].v=u;e[cnt].c=;e[cnt].f=;e[cnt].ne=h[v];h[v]=cnt;
}
int cur[N],d[N],vis[N];
int q[N],head,tail;
bool bfs(){
head=tail=;
memset(vis,,sizeof(vis));
d[s]=;vis[s]=;q[tail++]=s;
while(head!=tail){
int u=q[head++];
for(int i=h[u];i;i=e[i].ne){
int v=e[i].v;
if(!vis[v]&&e[i].c>e[i].f){
vis[v]=;d[v]=d[u]+;
q[tail++]=v;
if(v==t) return true;
}
}
}
return false;
}
int dfs(int u,int a){
if(u==t||a==) return a;
int flow=,f;
for(int &i=cur[u];i;i=e[i].ne){
int v=e[i].v;
if(d[v]==d[u]+&&(f=dfs(v,min(e[i].c-e[i].f,a)))>){
flow+=f;
e[i].f+=f;
e[((i-)^)+].f-=f;
a-=f;
if(a==) break;
}
}
if(a) d[u]=-;
return flow;
}
int dinic(){
int flow=;
while(bfs()){
for(int i=s;i<=t;i++) cur[i]=h[i];
flow+=dfs(s,INF);
}
return flow;
}
//int Bin(int v){
// int l=1,r=m;
// while(l<r){
// int mid=(l+r)>>1;
// if(v<=b[mid].p) r=mid;
// else if(v>b[mid].p) l=mid+1;
// }
// return l;
//} void buildGraph(){
for(int i=;i<=m;i++) ins(n+n+i,n+n+m+i,b[i].k);
for(int i=;i<=n;i++){
ins(s,i,);ins(n+i,t,);
int now=i;
for(int j=;j<=m;j++){
if(b[j].p<a[i].l) continue;
if(b[j].p>a[i].r) break;
ins(now,n+n+j,);
now=n+n+m+j;
}
ins(now,n+i,);
}
}
void getMP(){
sort(b+,b++n);
int p=;b[++p]=b[];
for(int i=;i<=m;i++)
if(b[i].p!=b[i-].p) b[++p]=b[i];
m=p;
}
int main(int argc, const char * argv[]){
n=read();m=read();
for(int i=;i<=n;i++) a[i].l=read(),a[i].r=read();
for(int i=;i<=m;i++) b[i].p=read(),b[i].k=read();
getMP();s=;t=n+n+m+m+;
buildGraph();
printf("%d",dinic());
return ;
}
网络流
正解是贪心 从左到右考虑每一个点和线段 这个点不满足条件就删除覆盖它的且r最大的线段
实现起来有好多做法,标程用了set维护覆盖当前考虑点的所有线段
好多人用了线段树(和矩形面积并类似),然而并不明白它们怎么找的线段
其实加减线段 询问一个点覆盖次数直接差分后用树状数组就好了.....然后用一个堆维护当前加入的所有线段为了取出r最大的线段
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
typedef long long ll;
const int N=4e5+,M=1e6+;
inline int read(){
char c=getchar();int x=,f=;
while(c<''||c>''){if(c=='-')f=-; c=getchar();}
while(c>=''&&c<=''){x=x*+c-''; c=getchar();}
return x*f;
}
int n,m;
int mp[M];
void iniMP(){
sort(mp+,mp++mp[]);
int p=;
mp[++p]=mp[];
for(int i=;i<=mp[];i++) if(mp[i]!=mp[i-]) mp[++p]=mp[i];
mp[]=p;
}
inline int Bin(int v){
int l=,r=mp[];
while(l<=r){
int mid=(l+r)>>;
if(v==mp[mid]) return mid;
else if(v<mp[mid]) r=mid-;
else l=mid+;
}
return ;
} int c[M];
inline int lowbit(int x){return x&-x;}
inline void add(int p,int v){for(;p<=mp[];p+=lowbit(p)) c[p]+=v;}
inline int sum(int p){
int re=;
for(;p>;p-=lowbit(p)) re+=c[p];
return re;
}
struct Segment{
int l,r;
bool operator <(const Segment &a)const{return l<a.l;}
}s[N];
struct Point{
int p,x;
bool operator <(const Point &a)const{return p<a.p;}
}a[N];
struct Node{
int r,id;
bool operator <(const Node &a)const{return r<a.r;}
Node(int a=,int b=):r(a),id(b){}
};
priority_queue<Node> q;
int ans;
void solve(){
for(int i=;i<=n;i++) s[i].l=Bin(s[i].l),s[i].r=Bin(s[i].r);
for(int i=;i<=m;i++) a[i].p=Bin(a[i].p);
sort(s+,s++n);
sort(a+,a++m);
for(int i=,j=;i<=m;i++){
for(;j<=n&&s[j].l<=a[i].p;j++){
add(s[j].l,);
add(s[j].r,-);
q.push(Node(s[j].r,j));ans++;
}
while(sum(a[i].p)>a[i].x){
int x=q.top().id; q.pop();ans--;
add(s[x].l,-);
add(s[x].r,);
}
}
printf("%d",ans);
}
int main(int argc, const char * argv[]){
n=read();m=read();
for(int i=;i<=n;i++)
mp[++mp[]]=s[i].l=read(),mp[++mp[]]=s[i].r=read()+; for(int i=;i<=m;i++)
mp[++mp[]]=a[i].p=read(),a[i].x=read();
iniMP();
solve();
return ;
}
D 洛谷 P3602 Koishi Loves Segments [贪心 树状数组+堆]的更多相关文章
- 洛谷P3602 Koishi Loves Segments 贪心
正解:贪心 解题报告: 传送门! 首先在学习贪心的入门题的时候我们就知道,当x=1的时候,也就是每条线段不能相交的时候的做法——就按右端点排序然后能选就选,也就是会议安排问题,原因显然?就你选右端点更 ...
- 洛谷P3602 Koishi Loves Segments(贪心,multiset)
洛谷题目传送门 贪心小水题. 把线段按左端点从小到大排序,限制点也是从小到大排序,然后一起扫一遍. 对于每一个限制点实时维护覆盖它的所有线段,如果超过限制,则贪心地把右端点最大的线段永远删去,不计入答 ...
- [NOIP2013提高&洛谷P1966]火柴排队 题解(树状数组求逆序对)
[NOIP2013提高&洛谷P1966]火柴排队 Description 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相 ...
- 洛谷P5069 [Ynoi2015]纵使日薄西山(树状数组,set)
洛谷题目传送门 一血祭 向dllxl致敬! 算是YNOI中比较清新的吧,毕竟代码只有1.25k. 首先我们对着题意模拟,寻找一些思路. 每次选了一个最大的数后,它和它周围两个数都要减一.这样无论如何, ...
- BZOJ3262/洛谷P3810 陌上花开 分治 三维偏序 树状数组
原文链接http://www.cnblogs.com/zhouzhendong/p/8672131.html 题目传送门 - BZOJ3262 题目传送门 - 洛谷P3810 题意 有$n$个元素,第 ...
- 洛谷 P4396 (离散化+莫队+树状数组)
### 洛谷P4396 题目链接 ### 题目大意: 有 n 个整数组成的数组,m 次询问,每次询问中有四个参数 l ,r,a,b .问你在[l,r] 的区间内的所有数中,值属于[a,b] 的数的个 ...
- [P4064][JXOI2017]加法(贪心+树状数组+堆)
题目描述 可怜有一个长度为 n 的正整数序列 A,但是她觉得 A 中的数字太小了,这让她很不开心. 于是她选择了 m 个区间 [li, ri] 和两个正整数 a, k.她打算从这 m 个区间里选出恰好 ...
- 【题解】洛谷P1966 [NOIP2013TG] 火柴排队(树状数组+逆序对)
次元传送门:洛谷P1966 思路 显然在两排中 每排第i小的分别对应就可取得最小值(对此不给予证明懒) 所以我们只在意两排的火柴是第几根 高度只需要用来进行排序(先把两个序列改成有序的方便离散化) 因 ...
- 洛谷P3246 [HNOI2016]序列(离线 差分 树状数组)
题意 题目链接 Sol 好像搞出了一个和题解不一样的做法(然而我考场上没写出来还是爆零0) 一个很显然的思路是考虑每个最小值的贡献. 预处理出每个数左边第一个比他小的数,右边第一个比他大的数. 那么\ ...
随机推荐
- 一步步教你创建自己的数字货币(代币)进行ICO
本文从技术角度详细介绍如何基于以太坊ERC20创建代币的流程. 写在前面 本文所讲的代币是使用以太坊智能合约创建,阅读本文前,你应该对以太坊.智能合约有所了解,如果你还不了解,建议你先看以太坊是什么 ...
- node学习笔记1——require参数查找策略
require参数类型 http.fs.path等,原生模块 ./mod或../mod,相对路径的文件模块 /pathtomodule/mod,绝对路径的文件模块 mod,非原生模块的文件模块 mo ...
- Spark算子--first、count、reduce、collect、lookup
转载请标明出处http://www.cnblogs.com/haozhengfei/p/4b8582c8dde1529abb11e4ccc8296171.html first.count.reduce ...
- java中static关键字的继承问题
结论:java中静态属性和静态方法可以被继承,但是没有被重写(overwrite)而是被隐藏. 原因: 1). 静态方法和属性是属于类的,调用的时候直接通过类名.方法名完成对,不需要继承机制及可以调用 ...
- iptables命令 高级网络
http://man.linuxde.net/iptables iptables命令是Linux上常用的防火墙软件,是netfilter项目的一部分.可以直接配置,也可以通过许多前端和图形界面配置. ...
- addslashes() 函数返回在预定义字符之前添加反斜杠的字符串
. 预定义字符是: 单引号(') 双引号(") 反斜杠(\) NULL 提示:该函数可用于为存储在数据库中的字符串以及数据库查询语句准备字符串. 注释:默认地,PHP 对所有的 GET.PO ...
- 阿里巴巴Java开发手册评
2016年底的时候阿里巴巴公开了其在内部使用的Java编程规范.随后进行了几次版本修订,目前的版本为v1.0.2版.下载地址可以在其官方社区-云栖社区https://yq.aliyun.com/art ...
- pyspider解析
https://www.cnblogs.com/microman/p/6111711.html #!/usr/bin/env python # -*- encoding: utf-8 -*- # Cr ...
- 堡垒机之paramiko模块
一.paramiko简单介绍 场景预设: 很多运维人员平时进行维护linux/unix主机时候,无非通过ssh到相应主机操作,那么一旦主机有成千上百台,那该如何应对,这时候我们需要批处理工具,基于py ...
- 【bird-java】分布式服务间的事件总线EventBus
什么是EventBusEventBus是对发布-订阅模式的一种实现.其以一种非常优雅的方式实现了组件间的解耦与通信,在Android开发.DDD等领域都有非常广泛的应用. 事件流大致如下: Produ ...