博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
UOJ356 [JOI2017春季合宿] Port Facility 【启发式合并】【堆】【并查集】
阅读量:4489 次
发布时间:2019-06-08

本文共 3223 字,大约阅读时间需要 10 分钟。

题目分析:

好像跑得很快,似乎我是第一个启发式合并的。

把玩具看成区间。首先很显然如果有两个玩具的进出时间有$l1<l2<r1<r2$的关系,那么这两个玩具一定在不同的栈中间。

现在假设一定有解,我们怎么得到答案呢?排序会使得计算变得方便,下面我们按照左端点排序。

想象一条扫描线,从左往右,当它遇到了一个区间的左端点的时候,我们尝试着将原先不在一起的合并,所有和这个不同栈的都被合并。

我们可以想象一个并查集,使用堆维护并查集。堆内存储并查集内元素的右端点。在最外面再用一个大堆来存储每个并查集的右端最小值(堆套堆)

实际上在每个并查集唯一要考虑的是在当前扫描线右端的最小的点的位置。若它不在当前玩具控制的区间内则该并查集一定不被该玩具影响。

否则将它提取出来,然后对并查集启发式合并。不仅如此,当前考虑的玩具也被合并在内。

现在考虑无解。无解实际上是冲突,如果有两个互异玩具集合,如果新出现一个玩具和其它两个不兼容则无解。

在上面的基础上,我们要做的只有把一个并查集再分裂成两个部分,然后两个部分分开合并即可。

时间复杂度$O(nlogn)$

1 #include
2 using namespace std; 3 typedef pair
pr; 4 5 const int maxn = (1<<21)+5; 6 const int mod = 1000000007; 7 struct line{
int l,r,num;}A[maxn]; 8 int cnt,n,im[maxn]; 9 10 void read(){11 scanf("%d",&n);12 for(int i=1;i<=n;i++)scanf("%d%d",&A[i].l,&A[i].r),A[i].num=i;13 sort(A+1,A+n+1,[](line a,line b){
return a.l < b.l;});14 }15 16 priority_queue
,greater
> pq;17 priority_queue
,greater
> s[maxn>>1],t[maxn>>1];18 int um,rs[maxn],num;19 void work(){20 for(int i=1;i<=n;i++) s[i].push(A[i].r);21 for(int i=1;i<=n;i++){22 while(!pq.empty()){23 pr k = pq.top(); if(k.first > A[i].l) break; pq.pop();24 if(s[k.second].size() && s[k.second].top() == k.first) s[k.second].pop();25 else t[k.second].pop();26 if(!s[k.second].size() && !t[k.second].size()) cnt++;27 else{28 if(!t[k.second].size()) {pq.push(make_pair(s[k.second].top(),k.second));continue;}29 if(!s[k.second].size()) {pq.push(make_pair(t[k.second].top(),k.second));continue;}30 if(s[k.second].size() && t[k.second].size())31 pq.push(make_pair(min(s[k.second].top(),t[k.second].top()),k.second));32 }33 }34 if(pq.empty()){pq.push(make_pair(A[i].r,i));continue;}35 um = i;int place = 0;num = 0;36 while(!pq.empty()){pr k = pq.top();if(k.first < A[i].r) {rs[++num] = k.second;pq.pop();}else break;}37 for(int j=1;j<=num;j++){38 int zeta = rs[j];39 if(s[zeta].size() && t[zeta].size() && s[zeta].top() < A[i].r && t[zeta].top() < A[i].r){40 puts("0");return;41 }42 int sum1 = s[um].size() + t[um].size(),sum2 = s[zeta].size()+t[zeta].size();43 if(sum1 > sum2){44 if((s[zeta].size() && s[zeta].top() < A[i].r) ^ place){45 while(t[zeta].size()){s[um].push(t[zeta].top());t[zeta].pop();}46 while(s[zeta].size()){t[um].push(s[zeta].top());s[zeta].pop();}47 }48 else{49 while(s[zeta].size()){s[um].push(s[zeta].top());s[zeta].pop();}50 while(t[zeta].size()){t[um].push(t[zeta].top());t[zeta].pop();}51 }52 }else{53 if((s[zeta].size() && s[zeta].top() < A[i].r) ^ place){54 while(t[um].size()){s[zeta].push(t[um].top());t[um].pop();}55 while(s[um].size()){t[zeta].push(s[um].top());s[um].pop();}56 place ^= 1;57 }else{58 while(s[um].size()){s[zeta].push(s[um].top());s[um].pop();}59 while(t[um].size()){t[zeta].push(t[um].top());t[um].pop();}60 }61 um = zeta;62 }63 }64 if(!t[um].size())pq.push(make_pair(s[um].top(),um));65 else if(!s[um].size()) pq.push(make_pair(t[um].top(),um));66 else pq.push(make_pair(min(s[um].top(),t[um].top()),um));67 }68 while(!pq.empty()){cnt++;pq.pop();}69 int ans = 1;while(cnt--){ans*=2;ans%=mod;}70 printf("%d",ans);71 }72 73 int main(){74 read();75 work();76 return 0;77 }

 

转载于:https://www.cnblogs.com/Menhera/p/9277444.html

你可能感兴趣的文章
简介几种负载均衡原理
查看>>
micropython logging文档
查看>>
Web站点风格切换的实现
查看>>
Python 文件操作
查看>>
免费后台管理UI界面、html源码推荐
查看>>
Topcoder SRM 656 (Div.1) 250 RandomPancakeStack - 概率+记忆化搜索
查看>>
python学习-- Django根据现有数据库,自动生成models模型文件
查看>>
github第一步之初始化操作
查看>>
《CoderXiaoban团队》第一次作业:团队亮相
查看>>
使用vue脚手架vue-cli搭建项目
查看>>
四轴飞行器Bootloader和固件的更新
查看>>
NLP之电影评分数据的情感分析
查看>>
常用网站颜色代码
查看>>
【bzoj1593-预定旅馆】线段树维护连续区间
查看>>
Maven的Scored介绍
查看>>
cookie 和session 的区别详解
查看>>
【Java】 大话数据结构(5) 线性表之双向链表
查看>>
【Java】 大话数据结构(6) 栈的顺序与链式存储
查看>>
java 断点续传(springMvc),可支持html5 vedio在线播放 posted @ 2017年3月11日 16:15:44...
查看>>
[入门阅读]怎样在android中解析JSON
查看>>