UOJ356 [JOI2017春季合宿] Port Facility 【启发式合并】【堆】【并查集】
题目分析:
好像跑得很快,似乎我是第一个启发式合并的。
把玩具看成区间。首先很显然如果有两个玩具的进出时间有$l1<l2<r1<r2$的关系,那么这两个玩具一定在不同的栈中间。
现在假设一定有解,我们怎么得到答案呢?排序会使得计算变得方便,下面我们按照左端点排序。
想象一条扫描线,从左往右,当它遇到了一个区间的左端点的时候,我们尝试着将原先不在一起的合并,所有和这个不同栈的都被合并。
我们可以想象一个并查集,使用堆维护并查集。堆内存储并查集内元素的右端点。在最外面再用一个大堆来存储每个并查集的右端最小值(堆套堆)
实际上在每个并查集唯一要考虑的是在当前扫描线右端的最小的点的位置。若它不在当前玩具控制的区间内则该并查集一定不被该玩具影响。
否则将它提取出来,然后对并查集启发式合并。不仅如此,当前考虑的玩具也被合并在内。
现在考虑无解。无解实际上是冲突,如果有两个互异玩具集合,如果新出现一个玩具和其它两个不兼容则无解。
在上面的基础上,我们要做的只有把一个并查集再分裂成两个部分,然后两个部分分开合并即可。
时间复杂度$O(nlogn)$
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pr; const int maxn = (<<)+;
const int mod = ;
struct line{int l,r,num;}A[maxn];
int cnt,n,im[maxn]; void read(){
scanf("%d",&n);
for(int i=;i<=n;i++)scanf("%d%d",&A[i].l,&A[i].r),A[i].num=i;
sort(A+,A+n+,[](line a,line b){return a.l < b.l;});
} priority_queue<pr,vector<pr>,greater<pr> > pq;
priority_queue<int,vector<int>,greater<int> > s[maxn>>],t[maxn>>];
int um,rs[maxn],num;
void work(){
for(int i=;i<=n;i++) s[i].push(A[i].r);
for(int i=;i<=n;i++){
while(!pq.empty()){
pr k = pq.top(); if(k.first > A[i].l) break; pq.pop();
if(s[k.second].size() && s[k.second].top() == k.first) s[k.second].pop();
else t[k.second].pop();
if(!s[k.second].size() && !t[k.second].size()) cnt++;
else{
if(!t[k.second].size()) {pq.push(make_pair(s[k.second].top(),k.second));continue;}
if(!s[k.second].size()) {pq.push(make_pair(t[k.second].top(),k.second));continue;}
if(s[k.second].size() && t[k.second].size())
pq.push(make_pair(min(s[k.second].top(),t[k.second].top()),k.second));
}
}
if(pq.empty()){pq.push(make_pair(A[i].r,i));continue;}
um = i;int place = ;num = ;
while(!pq.empty()){pr k = pq.top();if(k.first < A[i].r) {rs[++num] = k.second;pq.pop();}else break;}
for(int j=;j<=num;j++){
int zeta = rs[j];
if(s[zeta].size() && t[zeta].size() && s[zeta].top() < A[i].r && t[zeta].top() < A[i].r){
puts("");return;
}
int sum1 = s[um].size() + t[um].size(),sum2 = s[zeta].size()+t[zeta].size();
if(sum1 > sum2){
if((s[zeta].size() && s[zeta].top() < A[i].r) ^ place){
while(t[zeta].size()){s[um].push(t[zeta].top());t[zeta].pop();}
while(s[zeta].size()){t[um].push(s[zeta].top());s[zeta].pop();}
}
else{
while(s[zeta].size()){s[um].push(s[zeta].top());s[zeta].pop();}
while(t[zeta].size()){t[um].push(t[zeta].top());t[zeta].pop();}
}
}else{
if((s[zeta].size() && s[zeta].top() < A[i].r) ^ place){
while(t[um].size()){s[zeta].push(t[um].top());t[um].pop();}
while(s[um].size()){t[zeta].push(s[um].top());s[um].pop();}
place ^= ;
}else{
while(s[um].size()){s[zeta].push(s[um].top());s[um].pop();}
while(t[um].size()){t[zeta].push(t[um].top());t[um].pop();}
}
um = zeta;
}
}
if(!t[um].size())pq.push(make_pair(s[um].top(),um));
else if(!s[um].size()) pq.push(make_pair(t[um].top(),um));
else pq.push(make_pair(min(s[um].top(),t[um].top()),um));
}
while(!pq.empty()){cnt++;pq.pop();}
int ans = ;while(cnt--){ans*=;ans%=mod;}
printf("%d",ans);
} int main(){
read();
work();
return ;
}
UOJ356 [JOI2017春季合宿] Port Facility 【启发式合并】【堆】【并查集】的更多相关文章
- [JOI2017春季合宿]Port Facility[set、二分图]
题意 你有两个栈,有 \(n\) 个货物,每个货物有一个进栈时间和出栈时间(所有时间的并集是1~2n),问有多少种不同的入栈方案. \(n\le 10^6\) 分析 把每个货物的存在看成区间,相交的区 ...
- BZOJ 2733 [HNOI2012]永无乡(启发式合并+Treap+并查集)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2733 [题目大意] 给出n个点,每个点都有自己的重要度,现在有连边操作和查询操作, 查 ...
- UOJ356 【JOI2017春季合宿】Port Facility
暴力就是O(n^2)连边,二分图,这样只有22分. 我们考虑优化建边,我们按照左端点排序,对于一个新加进来的线段,我们向左端点距其最近的和他相交的线段连边,别的相交的我们连同色边,当一个点连了两条同色 ...
- UOJ #356. 【JOI2017春季合宿】Port Facility
Description 小M有两个本质不同的栈. 无聊的小M找来了n个玩具.之后小M把这n个玩具随机顺序加入某一个栈或把他们弹出. 现在小M告诉你每个玩具的入栈和出栈时间,现在她想考考小S,有多少种方 ...
- 【JOI2017春季合宿】Port Facility
http://uoj.ac/problem/356 题解 思路和\(NOIP\)双栈排序差不多. 对于两个元素,若\(l_1<l_2<r_1<r_2\)那么它们不能在一个栈里,我们连 ...
- UOJ #357. 【JOI2017春季合宿】Sparklers
Description 小S和小M去看花火大会. 一共有 n 个人按顺序排成一排,每个人手上有一个仅能被点燃一次的烟花.最开始时第 K 个人手上的烟花是点燃的. 烟花最多能燃烧 T 时间.每当两个人的 ...
- JOI2017 春季合宿:Railway Trip
自己的AC做法似乎离正解偏了十万八千里而且复杂了不少--不管怎样还是记录下来吧. 题意: 题目链接: JOISC2017 F - AtCoder JOISC2017 F - LOJ \(N\)个车站排 ...
- BZOJ 4388 [JOI2012春季合宿]Invitation (线段树、二叉堆、最小生成树)
题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=4388 题解 模拟Prim算法? 原题所述的过程就是Prim算法求最大生成树的过程.于是我 ...
- BZOJ 4221 [JOI2012春季合宿]Kangaroo (DP)
题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=4221 题解 orz WYC 爆切神仙DP 首先将所有袋鼠按大小排序.考虑从前往后DP, ...
随机推荐
- 四、xadmin自定义插件1
插件原理: Xadmin中每个页面都是一个AdminView对象返回的HTTPResponse结果. Xdamin插件所做的事情就是其实就是在AdminView执行过程中改变其执行逻辑或是改变其返回的 ...
- windows中在vs code终端使用bash
vs code Visual Studio Code的缩写,很好用的一个编辑器. 终端 vs code的终端(命令行)在windows中,默认使用的是powershell,如下图所示: powersh ...
- httpd sshd firewalld 服务后面的d的意思
在操作系统中,一般系统的服务都是以后台进程的方式存在,而且都会常驻系统中,直到关机才结束.这类服务也称Daemon,在Linux系统中就包含许多的Daemon. 判断Daemon最简单的方法就是从名称 ...
- [转帖]NUMA
作者:ibless 来源:CSDN 原文:https://blog.csdn.net/ibless/article/details/80114009 其实 很早之前对这一块有了解 比较多的的是 CCN ...
- 谈谈B-树和B+树及其应用
待更!!! B-树和B+树的应用:数据搜索和数据库索引 B+/-Tree原理及mysql的索引分析 从B树.B+树.B*树谈到R 树 B树.B-树.B+树.B*树
- vue cli3 vue.config.js 配置详情
module.exports = { // 基本路径 baseUrl: process.env.NODE_ENV === 'production' ? '/' : '/', ...
- Linux基础学习笔记2-文件管理和重定向
本节内容 1)文件系统结构元素 2)创建和查看文件 3)复制.转移和删除文件 4)软和硬链接 5)三种I/O设备 6)把I/O重定向至文件 7)使用管道 文件系统和结构 文件系统 文件和目录被组织成一 ...
- ssh 登陆服务器原理
这里分两种情况,这两种情况都涉及到公钥加密的概念. 由于公钥加密概念作为基础就不在本文进行讨论了. 使用ssh对远程服务器进行密码登录发生了什么: 客户端通过ssh连接服务器 1. 首先服务器把自己的 ...
- 开机自动获取spark用户名和服务器
import os.path import getpass import platform import time username = getpass.getuser() #获取当前用户名 home ...
- H5的使用
1.h5的部分标签浏览器兼容性问题 解决方案: <head> <!--[if lt IE 9]> <script src="http://cdn.static ...