洛谷 P7913 [CSP

洛谷 P7913 [CSP

    正在检查是否收录...

题目描述请移步 https://www.luogu.com.cn/problem/P7913

  • 题目简述

有一座机场,分为国际区和国外区,机场共有

n

个廊桥,国内国际分别有

m1

,

m2

架飞机,给定每架飞机抵达时刻

a[i]

、离开时刻

b[i]

对于每架飞机,若该区仍有廊桥空闲,就

必须

停靠在廊桥,否则停靠远机位(数量足够)

求将n个廊桥分配给国内区和国际区,停靠廊桥的飞机最多有多少架

  • 题目分析

首先注意到飞机是有后效性的,先到达的飞机可能会占用一个廊桥直到它离开,因此需要对每架飞机按到达时间进行排序

image

遍历每架飞机复杂度为

O(m1+m2)

,而 m1+m2 就达到了 10^5 级别

因此累加贡献部分的复杂度须为

O(log n)

  • 解题思路

发现对于每架飞机,如果它在有 x 个廊桥时停靠廊桥,那么有 x+1 个廊桥时它必定停靠廊桥

点击查看证明
假设 x=2 ,为方便,第i架飞机用 p[i] 来表示 不管数据具体是什么,这两个廊桥的使用必定与下图相似 廊桥1:p[1] --> p[3] -> p[4] ---------> p[9] 廊桥2:p[2] ---------------> p[7] (后面 “上一架飞机” 意为使用同一廊桥的上一架飞机) 每架飞机后面跟的都是首个到达时间比它离开时间晚的飞机(不考虑其他廊桥的占用) 若第 i 架飞机在两个廊桥时停靠廊桥,而三个廊桥时不停靠廊桥,则只可能其上一架飞机未停靠廊桥 以此类推,只有第 i 架飞机上一架的上一架... 即首个停靠原第 i 架飞机所停靠的廊桥的飞机未停靠廊桥,才可能成立 而新设一个廊桥并不影响原廊桥第一架停靠的飞机,因此这种情况不可能发生 

因此,每架飞机对答案的贡献,是一个 min_can~n 的区间(令 min_can 为最小的可让这架飞机停靠廊桥的廊桥数量)

考虑使用线段树、树状数组等 log n 级别的结构来解决

这是我们只需维护每架飞机的 "min_can" 就行了,这里分两种情况讨论

1.这架飞机(p[i])到达时有飞机(p[j])离开了,那么 min_can[x]=min_can[j]
2.这架飞机到达时没有飞机离开,则 min_can[x]=目前所有没离开的飞机的数量

要注意的是,一架飞机到达时可能有多架飞机离开,那么它之后的几架飞机仍可以从情况1转移

  • 代码实现
#include <iostream> #include <utility> #include <algorithm> #include <cstring> #include <queue> #define int long long using namespace std; const int MAX=1e5+7; int n,m1,m2; pair <int,int> p1[MAX],p2[MAX];//飞机 //priority_queue升序 priority_queue <pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q1,q2;//<离开时间,第几架> priority_queue <int,vector<int>,greater<int> > mc1,mc2;//所有离开的飞机,维护并找到最小的min_can int min_can1[MAX],min_can2[MAX];//最少多少个廊桥才能使第i架飞机降落在廊桥 int tr1[MAX],tr2[MAX];//树状数组 int lowbit(int x){ return x&-x; } void add1(int pos){ for(int i=pos;i<=m1;i+=lowbit(i)){ tr1[i]++; } } void add2(int pos){ for(int i=pos;i<=m2;i+=lowbit(i)){ tr2[i]++; } } int query1(int pos){ int res=0; for(int i=pos;i>=1;i-=lowbit(i)){ res+=tr1[i]; } return res; } int query2(int pos){ int res=0; for(int i=pos;i>=1;i-=lowbit(i)){ res+=tr2[i]; } return res; } signed main(){ cin>>n>>m1>>m2; n=min(n,m1+m2); for(int i=1;i<=m1;i++){ cin>>p1[i].first>>p1[i].second; } for(int i=1;i<=m2;i++){ cin>>p2[i].first>>p2[i].second; } sort(p1+1,p1+m1+1); sort(p2+1,p2+m2+1);//按first升序 memset(min_can1,0x3f,sizeof(min_can1)); memset(min_can2,0x3f,sizeof(min_can2));//初始化极大值 for(int i=1;i<=m1;i++){ while(!q1.empty()&&q1.top().first<p1[i].first){ mc1.push(min_can1[q1.top().second]);//将离开的飞机的min_can值推入另一个优先队列 q1.pop(); } q1.push(make_pair(p1[i].second,i)); if(!mc1.empty()){//有未利用的离开的飞机 add1(mc1.top()); min_can1[i]=mc1.top(); mc1.pop(); }else{ add1(q1.size());//未离开的飞机的数量 min_can1[i]=q1.size();//更改min_can的值 } } for(int i=1;i<=m2;i++){//同上 while(!q2.empty()&&q2.top().first<p2[i].first){ mc2.push(min_can2[q2.top().second]); q2.pop(); } q2.push(make_pair(p2[i].second,i)); if(!mc2.empty()){ add2(mc2.top()); min_can2[i]=mc2.top(); mc2.pop(); }else{ add2(q2.size()); min_can2[i]=q2.size(); } } int ans=-1; for(int i=0;i<=n;i++){ ans=max(ans,query1(i)+query2(n-i));//合并答案 } cout<<ans; } 

完结撒花qwq

  • 本文作者:WAP站长网
  • 本文链接: https://wapzz.net/post-27899.html
  • 版权声明:本博客所有文章除特别声明外,均默认采用 CC BY-NC-SA 4.0 许可协议。
本站部分内容来源于网络转载,仅供学习交流使用。如涉及版权问题,请及时联系我们,我们将第一时间处理。
文章很赞!支持一下吧 还没有人为TA充电
为TA充电
还没有人为TA充电
0
0
  • 支付宝打赏
    支付宝扫一扫
  • 微信打赏
    微信扫一扫
感谢支持
文章很赞!支持一下吧
关于作者
2.8W+
9
1
2
WAP站长官方

码奴蒋老师

上一篇

【EF Core】实体类的依赖注入

下一篇
评论区
内容为空

这一切,似未曾拥有

  • 复制图片
按住ctrl可打开默认菜单