【IOI1998】Picture(扫描线+线段树)

时间:2022-06-05 04:49:40

问题来源:IOI1998 D2T1

题意:就是在一个平面内给出n个矩形,叫你计算将这些矩形合并以后,新图形的周长。

例如:

【IOI1998】Picture(扫描线+线段树)【IOI1998】Picture(扫描线+线段树)

上图是原本的矩形们      ---------->合并后的图形

解题思路:拿一条扫描线横着扫一次,遇到左边的边就在这条扫描线上+1,遇到右边的边就在这条扫描线上-1,在边被扫到的时候计算一下线上为0的个数即可。

  因为如果只是单纯的For循环累加,时间会爆,所以我们采用线段树来存这条扫描线的状态优化效率即可。然后竖着再做同样的事做一遍。

  时间效率应该是O(kn)(k是常数)。

附代码:

 #include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#define For(i,a,b) for (int i=a; i<=b; i++)
#define Ford(i,a,b) for (int i=a; i>=b; i--)
#define File(fn) freopen(fn".in","r",stdin); freopen(fn".out","w",stdout);
#define mem(qaq,num) memset(qaq,num,sizeof(qaq));
#define ll long long
#define mod 1000000007
#define INF 2000000000
#define mid ((l+r)>>1)
using namespace std;
struct zxy{
int mi,n,mark;
}tr[];
struct edge{
int l,r,h,typ;
}x[],y[];
int n,ans,cnt;
inline int in(){
int x=,f=;
char ch=getchar();
while (ch<''||ch>'') f=ch=='-'?-:,ch=getchar();
while (ch>=''&&ch<='') x=x*+ch-'',ch=getchar();
return x*f;
}
inline void combine(int k){
if (tr[k<<].mi==tr[k<<|].mi) tr[k].n=tr[k<<].n+tr[k<<|].n,tr[k].mi=tr[k<<].mi;
else
if(tr[k<<].mi<tr[k<<|].mi) tr[k].n=tr[k<<].n,tr[k].mi=tr[k<<].mi;
else tr[k].n=tr[k<<|].n,tr[k].mi=tr[k<<|].mi;
return;
}
inline void built(int l,int r,int k){
if (l==r){
tr[k].mi=;
tr[k].n=;
tr[k].mark=;
return;
}
built(l,mid,k<<);
built(mid+,r,k<<|);
combine(k);
tr[k].mark=;
}
inline void pushdown(int k){
int ad=tr[k].mark;
tr[k<<].mark+=ad;
tr[k<<|].mark+=ad;
tr[k<<].mi+=ad;
tr[k<<|].mi+=ad;
tr[k].mark=;
return;
}
inline void update(int l,int r,int a,int b,int k,int ad){
if (l>=a&&b>=r){
tr[k].mark+=ad;
tr[k].mi+=ad;
return;
}
if (tr[k].mark) pushdown(k);
if (a<=mid) update(l,mid,a,b,k<<,ad);
if (b>mid) update(mid+,r,a,b,k<<|,ad);
combine(k);
return;
}
inline int query(int l,int r,int k,int a,int b){
if (l==a&&r==b){
if (tr[k].mi) return ;
return tr[k].n;
}
if (tr[k].mark) pushdown(k);
if (b<=mid) return query(l,mid,k<<,a,b);
if (a>mid) return query(mid+,r,k<<|,a,b);
return query(l,mid,k<<,a,mid)+query(mid+,r,k<<|,mid+,b);
}
void init(){
n=in();
For(i,,n){
int x1=in()+,y1=in()+,x2=in()+,y2=in()+;
x[++cnt].l=x1+,x[cnt].r=x2,x[cnt].h=y1,x[cnt].typ=;
y[cnt].l=y1+,y[cnt].r=y2,y[cnt].h=x1,y[cnt].typ=;
x[++cnt].l=x1+,x[cnt].r=x2,x[cnt].h=y2,x[cnt].typ=;
y[cnt].l=y1+,y[cnt].r=y2,y[cnt].h=x2,y[cnt].typ=;
}
return;
}
bool cmp(edge a,edge b){
return a.h<b.h||(a.h==b.h&&a.typ<b.typ);
}
void work(){
sort(x+,x+cnt+,cmp);
built(,,);
For(i,,cnt)
if (!x[i].typ){
ans+=query(,,,x[i].l,x[i].r);
update(,,x[i].l,x[i].r,,);
}
else{
update(,,x[i].l,x[i].r,,-);
ans+=query(,,,x[i].l,x[i].r);
}
sort(y+,y+cnt+,cmp);
built(,,);
For(i,,cnt)
if (!y[i].typ){
ans+=query(,,,y[i].l,y[i].r);
update(,,y[i].l,y[i].r,,);
}
else{
update(,,y[i].l,y[i].r,,-);
ans+=query(,,,y[i].l,y[i].r);
}
return;
}
int main(){
init();
work();
printf("%d",ans);
}

本文由Melacau编写,Melacau代表M星向您问好,如果您不是在我的博客http://www.cnblogs.com/Melacau上看到本文,请您向我联系,email:13960948839@163.com.

【IOI1998】Picture(扫描线+线段树)的更多相关文章

  1. luogu P1856 &lbrack;USACO5&period;5&rsqb;矩形周长Picture 扫描线 &plus; 线段树

    Code: #include<bits/stdc++.h> #define maxn 200007 #define inf 100005 using namespace std; void ...

  2. HDU 3642 - Get The Treasury - &lbrack;加强版扫描线&plus;线段树&rsqb;

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3642 Time Limit: 10000/5000 MS (Java/Others) Memory L ...

  3. 【BZOJ3958】&lbrack;WF2011&rsqb;Mummy Madness 二分&plus;扫描线&plus;线段树

    [BZOJ3958][WF2011]Mummy Madness Description 在2011年ACM-ICPC World Finals上的一次游览中,你碰到了一个埃及古墓. 不幸的是,你打开了 ...

  4. HDU 3265&sol;POJ 3832 Posters(扫描线&plus;线段树)(2009 Asia Ningbo Regional)

    Description Ted has a new house with a huge window. In this big summer, Ted decides to decorate the ...

  5. 【bzoj4491】我也不知道题目名字是什么 离线扫描线&plus;线段树

    题目描述 给定一个序列A[i],每次询问l,r,求[l,r]内最长子串,使得该子串为不上升子串或不下降子串 输入 第一行n,表示A数组有多少元素接下来一行为n个整数A[i]接下来一个整数Q,表示询问数 ...

  6. hdu1542 Atlantis(扫描线&plus;线段树&plus;离散)矩形相交面积

    题目链接:点击打开链接 题目描写叙述:给定一些矩形,求这些矩形的总面积.假设有重叠.仅仅算一次 解题思路:扫描线+线段树+离散(代码从上往下扫描) 代码: #include<cstdio> ...

  7. P3722 &lbrack;AH2017&sol;HNOI2017&rsqb;影魔(单调栈&plus;扫描线&plus;线段树)

    题面传送门 首先我们把这两个贡献翻译成人话: 区间 \([l,r]\) 产生 \(p_1\) 的贡献当且仅当 \(a_l,a_r\) 分别为区间 \([l,r]\) 的最大值和次大值. 区间 \([l ...

  8. HDU 1828 &sol; POJ 1177 Picture (线段树扫描线,求矩阵并的周长,经典题)

    做这道题之前,建议先做POJ 1151  Atlantis,经典的扫描线求矩阵的面积并 参考连接: http://www.cnblogs.com/scau20110726/archive/2013/0 ...

  9. &lbrack;矩形并-扫描线-线段树&rsqb;Picture

    最近在补数学和几何,没啥好写的,因为已经决定每天至少写一篇了,今天随便拿个题水水. 题目大意:给你N个边平行于坐标轴的矩形,求它们并的周长.(N<=5000) 思路:这个数据范围瞎暴力就过了,但 ...

随机推荐

  1. DHCP的若干原理解释

    转自:http://blog.chinaunix.net/uid-22287947-id-1775641.html 搜罗了几种关于dhcp的原理和过程解释 DHCP(Dynamic Host Conf ...

  2. sql 中实现往表中插入一条记录并返回当前记录的ID

    写一条存储过程,实现往User中插入一条记录并返回当前UserId(自增长id) --推荐写法 if(Exists(select * from sys.objects where name=N'Usp ...

  3. Guzzle – 构建 RESTful Web 服务的 PHP HTTP 框架

    Guzzle 减轻了发送 HTTP 请求和创建 Web 服务客户端的痛苦.它包含建立一个强大的网络服务客户端的工具,包括:服务描述定义的输入和输出的 API,资源迭代器遍历分页资源,尽可能有效地发送大 ...

  4. Android Service使用拾遗&lbrack;阿里工程师分享&rsqb;

    Service作为android的四大组件之一常用来帮助我们完成一些需要放在后台处理的任务,通过startService和bindService两种方式被调用.因为Service也是在主线程中运行的, ...

  5. Period&lbrack;HDU1358&rsqb;

    Period Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Sub ...

  6. 计算json的和

      var count=0;    for(var i=0;i<data.length;i++){        count+=data[i].data;   }

  7. 如何设置MySQL Workbench EER Diagram 尺寸?

    ER Diagram -> Model -> Diagram Properties and Size...

  8. Dockerfile里指定执行命令用ENTRYPOING和用CMD有何不同?

    结论:运行时机不太一样. RUN是在Build时运行的,先于CMD和ENTRYPOINT.Build完成了,RUN也运行完成后,再运行CMD或者ENTRYPOINT. ENTRYPOINT和CMD的不 ...

  9. Lotusscript统计在线用户数

    使用notessession的SendConsoleCommand方法向服务器控制台发送“show inetusers”命令,该命令返回一个结果(字符串),字符串类似如下: admin   192.1 ...

  10. 利用python实现二分法和斐波那契序列

    利用python实现二分法:我的实现思路如下 1.判断要查找的值是否大于最大值,如果大于则直接返回False 2.判断要查找的值是否小于最小值,如果小于则直接返回False 3.如果要查找的值在最大值 ...