【CF471E】MUH and Lots and Lots of Segments 扫描线+并查集+线段树+set
【CF471E】MUH and Lots and Lots of Segments
题意:给你平面上n条水平或竖直的,端点在整点处的线段。你需要去掉一些线段的一些部分,使得剩下的图形:1.连通,2.无环,3.端点依旧位于整点处。
$n\le 2\times 10^5$
题解:如果把整点看成点的话,那么这题让你求的就是一棵生成树。一棵生成树的边数就是这个连通块内点数-1,所以我们找到最大的连通块将其点数-1就是答案。
具体实现中,我们先进行扫描线,用并查集维护连通性,用线段树快速查找区间中点的数量以及一个点的前驱后继,用set维护所有所在连通块与后继所在连通块不同的点即可。
不知道为什么思考的过程中想到了Kruskal。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <set>
#define lson x<<1
#define rson x<<1|1
using namespace std;
const int maxn=200010;
typedef long long ll;
int n,m,np,nq;
int f[maxn<<1],org[maxn<<1];
ll ans;
ll ref[maxn<<1];
struct edge
{
int l,r,x;
}p[maxn],q[maxn<<1];
ll s[maxn<<3],sum[maxn<<1];
set<int> st;
set<int>::iterator it;
bool cmp(const edge &a,const edge &b)
{
return (a.x==b.x)?(a.r>b.r):(a.x<b.x);
}
int find(int x)
{
return (f[x]==x)?x:(f[x]=find(f[x]));
}
void updata(int l,int r,int x,int a,int b)
{
s[x]+=b;
if(l==r) return ;
int mid=(l+r)>>1;
if(a<=mid) updata(l,mid,lson,a,b);
else updata(mid+1,r,rson,a,b);
}
int count(int l,int r,int x,int a,int b)
{
if(a>b) return 0;
if(a<=l&&r<=b) return s[x];
int mid=(l+r)>>1;
if(b<=mid) return count(l,mid,lson,a,b);
if(a>mid) return count(mid+1,r,rson,a,b);
return count(l,mid,lson,a,b)+count(mid+1,r,rson,a,b);
}
int find(int l,int r,int x,int a)
{
if(l==r) return l;
int mid=(l+r)>>1;
if(a<=s[lson]) return find(l,mid,lson,a);
return find(mid+1,r,rson,a-s[lson]);
}
inline int pre(int x)
{
int t=count(1,m,1,1,x);
if(t==1) return -1;
return find(1,m,1,t-1);
}
inline int nxt(int x)
{
int t=count(1,m,1,1,x);
if(t==s[1]) return -1;
return find(1,m,1,t+1);
}
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+(gc^'0'),gc=getchar();
return ret*f;
}
int main()
{
n=rd();
int i,j,a,b,c,d;
ll tmp;
for(i=1;i<=n;i++)
{
a=rd(),b=rd(),c=rd(),d=rd();
if(b==d)
{
q[++nq].x=a,q[nq].l=b,q[nq].r=c-a+1;
q[++nq].x=c,q[nq].l=b,q[nq].r=0;
ref[++m]=b;
}
else
{
p[++np].x=a,p[np].l=b,p[np].r=d;
ref[++m]=b,ref[++m]=d;
ans=max(ans,ll(d-b));
}
}
sort(ref+1,ref+m+1);
for(i=1,j=0,ref[0]=-1<<30;i<=m;i++) if(ref[i]!=ref[j]) ref[++j]=ref[i];
m=j;
for(i=1;i<=nq;i++) q[i].l=lower_bound(ref+1,ref+m+1,q[i].l)-ref,f[i]=i;
for(i=1;i<=np;i++) p[i].l=lower_bound(ref+1,ref+m+1,p[i].l)-ref,p[i].r=lower_bound(ref+1,ref+m+1,p[i].r)-ref;
sort(p+1,p+np+1,cmp);
sort(q+1,q+nq+1,cmp);
for(i=j=1;i<=np;i++)
{
while(j<=nq&&(q[j].x<p[i].x||(q[j].x==p[i].x&&q[j].r)))
{
a=q[j].l,b=q[j].r;
if(b)
{
org[a]=j,sum[j]=b;
st.insert(a);
updata(1,m,1,a,1);
c=pre(a);
if(c!=-1) st.insert(c);
}
else
{
it=st.find(a);
if(it!=st.end()) st.erase(it);
c=pre(a);
if(c!=-1) st.insert(c);
updata(1,m,1,a,-1);
}
j++;
}
tmp=ref[p[i].r]-ref[p[i].l]+1-count(1,m,1,p[i].l,p[i].r);
a=p[i].l-1,c=nxt(a);
if(c<=p[i].r)
{
sum[find(org[c])]+=tmp;
while(1)
{
it=st.lower_bound(p[i].l);
if(it==st.end()||(*it)>p[i].r) break;
a=*it,c=nxt(a);
if(c==-1||c>p[i].r) break;
st.erase(it);
b=find(org[a]),d=find(org[c]);
if(b!=d) sum[d]+=sum[b],f[b]=d;
}
}
}
for(i=1;i<=nq;i++) ans=max(ans,sum[i]-1);
printf("%lld",ans);
return 0;
}
【CF471E】MUH and Lots and Lots of Segments 扫描线+并查集+线段树+set的更多相关文章
- Codeforces Round #337 (Div. 2) D. Vika and Segments 线段树 矩阵面积并
D. Vika and Segments Vika has an infinite sheet of squared paper. Initially all squares are whit ...
- Codeforces Round #337 (Div. 2) D. Vika and Segments 线段树扫描线
D. Vika and Segments 题目连接: http://www.codeforces.com/contest/610/problem/D Description Vika has an i ...
- POJ 1436 Horizontally Visible Segments (线段树·区间染色)
题意 在坐标系中有n条平行于y轴的线段 当一条线段与还有一条线段之间能够连一条平行与x轴的线不与其他线段相交 就视为它们是可见的 问有多少组三条线段两两相互可见 先把全部线段存下来 并按x ...
- Codeforces Round #535 (Div. 3) E2. Array and Segments (Hard version) 【区间更新 线段树】
传送门:http://codeforces.com/contest/1108/problem/E2 E2. Array and Segments (Hard version) time limit p ...
- POJ 1436 Horizontally Visible Segments(线段树)
POJ 1436 Horizontally Visible Segments 题目链接 线段树处理染色问题,把线段排序.从左往右扫描处理出每一个线段能看到的右边的线段,然后利用bitset维护枚举两个 ...
- (中等) POJ 1436 Horizontally Visible Segments , 线段树+区间更新。
Description There is a number of disjoint vertical line segments in the plane. We say that two segme ...
- codeforces 610D D. Vika and Segments(离散化+线段树+扫描线算法)
题目链接: D. Vika and Segments time limit per test 2 seconds memory limit per test 256 megabytes input s ...
- poj 3304 Segments(计算直线与线段之间的关系)
Segments Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 10921 Accepted: 3422 Descrip ...
- POJ 3304 Segments(判断直线与线段是否相交)
题目传送门:POJ 3304 Segments Description Given n segments in the two dimensional space, write a program, ...
随机推荐
- C# WebApi+Task+WebSocket实战项目演练(四)
一.课程介绍 本次分享课程属于<C#高级编程实战技能开发宝典课程系列>中的第四部分,阿笨后续会计划将实际项目中的一些比较实用的关于C#高级编程的技巧分享出来给大家进行学习,不断的收集.整理 ...
- JS中的算法与数据结构——排序(Sort)
排序算法(Sort) 引言 我们平时对计算机中存储的数据执行的两种最常见的操作就是排序和查找,对于计算机的排序和查找的研究,自计算机诞生以来就没有停止过.如今又是大数据,云计算的时代,对数据的排序和查 ...
- APP中的图片如何长按可以下载并保存图片到相册出错处理
https://www.cnblogs.com/interdrp/p/9302164.html 接上文. 如果用户在保存图片过程中,不小心拒绝了相册的访问权限
- ElasticSearch的基本原理与用法
一.简介 ElasticSearch和Solr都是基于Lucene的搜索引擎,不过ElasticSearch天生支持分布式,而Solr是4.0版本后的SolrCloud才是分布式版本,Solr的分布式 ...
- 第一章 java nio三大组件与使用姿势
本案例来源于<netty权威指南> 一.三大组件 Selector:多路复用器.轮询注册在其上的Channel,当发现某个或者多个Channel处于“就绪状态”后(accept接收连接事件 ...
- Elasticsearch跨集群搜索(Cross Cluster Search)
1.简介 Elasticsearch在5.3版本中引入了Cross Cluster Search(CCS 跨集群搜索)功能,用来替换掉要被废弃的Tribe Node.类似Tribe Node,Cros ...
- tmunx error:invalid option: status-utf8 invalid option: utf8
修改为:set-window-option -gq mouse off set-window-option -gq mode-mouse off set-option -gq status-utf8 ...
- unbuntu系统( PC机 )中安装360wifi步骤
少说废话,每一步都经过验证: 1. 首先查看一下当前使用的linux版本: gxjun@gxjun:~$ uname -r 4.8.0-59-generic 2. 将360wifi插入PC的USB中 ...
- 在IIS7上导出所有应用程序池的方法批量域名绑定(网站绑定)
资料来源: http://www.2cto.com/os/201410/341882.html 一点经验:导出配置文件后,建议打开看看,如果有需要调整的需要做修改. 在IIS7+上导出所有应用程序池的 ...
- 告别set和get,两大利器轻松搞定model转换
场景一:一般我们遇到需要新建model,常规做法就是创建一个类,老老实实的定义好model中的所有属性,一般来说属性对应的set方法和get方法都是少不了的,有时候还需要toString甚至equal ...