题目描述

Koishi喜欢线段。

她的条线段都能表示成数轴上的某个闭区间。Koishi喜欢在把所有线段都放在数轴上,然后数出某些点被多少线段覆盖了。

Flandre看她和线段玩得很起开心,就抛给她一个问题:

数轴上有个点突然兴奋,如果自己被身上覆盖了超过条线段,这个点就会浑身难受然后把Koishi批判一番。

Koishi十分善良,为了不让数轴上的点浑身难受,也为了让自己开心,她想在数轴上放入尽量多的线段。

按照套路,Koishi假装自己并不会做这道题,所以她就来求你帮忙。并承诺如果你解决了问题就给你打一通电话w。

输入输出格式

输入格式:

第一行两个个整数,分别表示插入的线段数和关键点数。

接下来行,每行两个整数,表示线段的端点。

接下来行,每行两个整数,表示有个位于的点突然兴奋,并认为自己身上不得覆盖超过条线段

输出格式:

一个整数,表示最多能放入的线段数

输入输出样例

输入样例#1:

4 3
1 3
2 4
5 7
6 8
2 5
3 1
6 2
输出样例#1:

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 [贪心 树状数组+堆]的更多相关文章

  1. 洛谷P3602 Koishi Loves Segments 贪心

    正解:贪心 解题报告: 传送门! 首先在学习贪心的入门题的时候我们就知道,当x=1的时候,也就是每条线段不能相交的时候的做法——就按右端点排序然后能选就选,也就是会议安排问题,原因显然?就你选右端点更 ...

  2. 洛谷P3602 Koishi Loves Segments(贪心,multiset)

    洛谷题目传送门 贪心小水题. 把线段按左端点从小到大排序,限制点也是从小到大排序,然后一起扫一遍. 对于每一个限制点实时维护覆盖它的所有线段,如果超过限制,则贪心地把右端点最大的线段永远删去,不计入答 ...

  3. [NOIP2013提高&洛谷P1966]火柴排队 题解(树状数组求逆序对)

    [NOIP2013提高&洛谷P1966]火柴排队 Description 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相 ...

  4. 洛谷P5069 [Ynoi2015]纵使日薄西山(树状数组,set)

    洛谷题目传送门 一血祭 向dllxl致敬! 算是YNOI中比较清新的吧,毕竟代码只有1.25k. 首先我们对着题意模拟,寻找一些思路. 每次选了一个最大的数后,它和它周围两个数都要减一.这样无论如何, ...

  5. BZOJ3262/洛谷P3810 陌上花开 分治 三维偏序 树状数组

    原文链接http://www.cnblogs.com/zhouzhendong/p/8672131.html 题目传送门 - BZOJ3262 题目传送门 - 洛谷P3810 题意 有$n$个元素,第 ...

  6. 洛谷 P4396 (离散化+莫队+树状数组)

    ### 洛谷P4396  题目链接 ### 题目大意: 有 n 个整数组成的数组,m 次询问,每次询问中有四个参数 l ,r,a,b .问你在[l,r] 的区间内的所有数中,值属于[a,b] 的数的个 ...

  7. [P4064][JXOI2017]加法(贪心+树状数组+堆)

    题目描述 可怜有一个长度为 n 的正整数序列 A,但是她觉得 A 中的数字太小了,这让她很不开心. 于是她选择了 m 个区间 [li, ri] 和两个正整数 a, k.她打算从这 m 个区间里选出恰好 ...

  8. 【题解】洛谷P1966 [NOIP2013TG] 火柴排队(树状数组+逆序对)

    次元传送门:洛谷P1966 思路 显然在两排中 每排第i小的分别对应就可取得最小值(对此不给予证明懒) 所以我们只在意两排的火柴是第几根 高度只需要用来进行排序(先把两个序列改成有序的方便离散化) 因 ...

  9. 洛谷P3246 [HNOI2016]序列(离线 差分 树状数组)

    题意 题目链接 Sol 好像搞出了一个和题解不一样的做法(然而我考场上没写出来还是爆零0) 一个很显然的思路是考虑每个最小值的贡献. 预处理出每个数左边第一个比他小的数,右边第一个比他大的数. 那么\ ...

随机推荐

  1. c++(hash表)

    hash表,有时候也被称为散列表.个人认为,hash表是介于链表和二叉树之间的一种中间结构.链表使用十分方便,但是数据查找十分麻烦:二叉树中的数据严格有序,但是这是以多一个指针作为代价的结果.hash ...

  2. c++(递归和堆栈)

    看过我前面博客的朋友都清楚,函数调用主要依靠ebp和esp的堆栈互动来实现的.那么递归呢,最主要的特色就是函数自己调用自己.如果一个函数调用的是自己本身,那么这个函数就是递归函数. 我们可以看一下普通 ...

  3. UEP-级联下拉

    级联查询在UEP中采用动态下拉的形式,cascadeid为关键字,注意jsp页面的id的相互嵌套关系, 数据库字段的数值的设置,和动态下拉SQL语句的书写. <td align="ce ...

  4. [国嵌攻略][054][NandFlash驱动设计_写]

    Nand Flash支持按页写和随机写两种方式,在下面实现的是按页写.闪存在写数据时,只能写入1,不能写入0,所以写函数必须和擦除函数一起使用,并且擦除函数是按块擦除. /************** ...

  5. 98、vue.js简单入门

    本篇导航: 介绍与安装 vue常用指令 一.介绍与安装 vue是一套构建用户界面的JAVASCRIPT框架.与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用.Vue 的核心库只关注视图层, ...

  6. iis配置完成,出现HTTP 错误 403.14 - Forbidden

    版权声明:本文为博主原创文章,未经博主允许不得转载.转载请标明文章出处和原文链接. 403.14 禁止访问:在 Web 服务器上已拒绝目录列表 解决方案一:一般情况站点都是不会允许直接读取目录内容的, ...

  7. java访问修饰符 public protect default private

    适用范围<访问权限范围越小,安全性越高>   访问权限   类   包  子类  其他包   public     ok   ok    ok     ok         (对所有可用的 ...

  8. jQuery.fn的作用是什么

    jQuery.fn的作用是什么:在自定义jQuery插件中,会经常见到jQuery.fn的身影,下面就简单介绍一下它的作用到底是什么.想要认识它的本质,最好的办法直接看jQuery的源码,否则一切都是 ...

  9. K8S API 调用

    不好意,本人比较懒,OneNote 复制粘贴的时候就是自动变成图片了.请各位看官多多见谅. 遗留问题: 目前pod仅支持修改 * and(),so...

  10. python文件操作总结

    python中对文件.文件夹(文件操作函数)的操作需要涉及到os模块和shutil模块. 得到当前工作目录,即当前Python脚本工作的目录路径: os.getcwd() 返回指定目录下的所有文件和目 ...