USACO 5.5 Picture
Picture
IOI 1998
A number, N (1 <= N < 5000), of rectangular posters, photographs and other pictures of the same shape are pasted on a wall. Their sides are all vertical or horizontal. Each rectangle can be partially or totally covered by the others. The length of the boundary of the union of all rectangles is called the perimeter. Write a program to calculate the perimeter.
Figure 1 shows an example with seven rectangles:
Figure 1. A set of seven rectangles
The corresponding boundary is the whole set of line segments drawn in Figure 2:
Figure 2. The boundary of the set of rectangles
The vertices of all rectangles have integer coordinates. All coordinates are in the range [-10000,10000] and any existing rectangle has a positive area. The numeric value of the result fits in a 32-bit signed representation.
PROGRAM NAME: picture
INPUT FORMAT
Line 1: | N, the number of rectangles pasted on the wall. |
Lines 2..N+1 | In each of the subsequent lines, one can find the integer coordinates of the lower left vertex and the upper right vertex of each rectangle. The values of those coordinates are given as ordered pairs consisting of an x-coordinate followed by a y-coordinate. |
SAMPLE INPUT (file picture.in)
7
-15 0 5 10
-5 8 20 25
15 -4 24 14
0 -6 16 4
2 15 10 22
30 10 36 20
34 0 40 16
OUTPUT FORMAT
A single line with a non-negative integer which corresponds to the perimeter for the input rectangles.
SAMPLE OUTPUT (file picture.out)
228 ———————————————————————————————————————————题解
这道题暴力完全可以做
/*
ID: ivorysi
LANG: C++
PROG: picture
*/
#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define siji(i,x,y) for(int i=(x);i<=(y);++i)
#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
#define sigongzi(j,x,y) for(int j=(x);j>(y);--j)
#define inf 0x5f5f5f5f
#define ivorysi
#define mo 97797977
#define hash 974711
#define base 47
#define fi first
#define se second
#define pii pair<int,int>
#define esp 1e-8
typedef long long ll;
using namespace std;
struct node {
int s,t,y,on;
node (int st=, int ed=, int ceng=, int num=) {//要写上初值
s=st;t=ed;y=ceng;on=num;
}
bool operator <(const node &b) const {
return y<b.y || (y==b.y&&on>b.on);
}
}seg[];
int n;
int lx[],rx[],ly[],ry[],ans,level[];
void solve() {
scanf("%d",&n);
siji(i,,n) {
scanf("%d%d%d%d",&lx[i],&ly[i],&rx[i],&ry[i]);
}
siji(i,,n) {
seg[i*-] = node(lx[i],rx[i],ly[i],);
seg[i*] = node(lx[i],rx[i],ry[i],-);
}
sort(seg+,seg+*n+);
siji(i,,*n) {
xiaosiji(j,seg[i].s,seg[i].t) {
if(level[j+]+seg[i].on== && level[j+]==) ++ans;
else if(level[j+]+seg[i].on== && level[j+]==) ++ans;
level[j+]+=seg[i].on;
}
}
siji(i,,n) {
seg[i*-] = node(ly[i],ry[i],lx[i],);
seg[i*] = node(ly[i],ry[i],rx[i],-);
}
sort(seg+,seg+*n+);
memset(level,,sizeof(level));
siji(i,,*n) {
xiaosiji(j,seg[i].s,seg[i].t) {
if(level[j+]+seg[i].on== && level[j+]==) ++ans;
else if(level[j+]+seg[i].on== && level[j+]==) ++ans;
level[j+]+=seg[i].on;
}
}
printf("%d\n",ans);
}
int main(int argc, char const *argv[])
{
#ifdef ivorysi
freopen("picture.in","r",stdin);
freopen("picture.out","w",stdout);
#else
freopen("f1.in","r",stdin);
#endif
solve();
return ;
}
哼,我可不是只是暴力可以做就暴力做的人
然后我用了许多种【奇奇怪怪而且错了的】线段树解法,让我深切的体会到我线段树学的是真不好
那么……
错解1
线段树区间加的模型,然后维护一个cover表示这个区间被覆盖了多少次,每次加上一个flag【如果这是矩形的底边flag=1,如果这是矩形的顶边flag=-1】
更新线段的时候,发现这个区间的cover=0,我们加上这个区间的长度*2
我们对于横向做一遍,对于纵向做一遍
……这,连样例都过不了
为什么呢,经过我gdb孜孜不倦的调试,我发现了原因……
如果这样的话我们需要加上5->9 *2 然而我们更新的话会直接刷掉0->9的cover
然后就有了
错解1.4
我们的区间可以是它左右两个区间的cover取个min嘛……
【然而这样有啥用?】
要不然就和自己的cover与左右两个区间的最小cover取个max……
【……啥】
错解1.47
我们的区间可以是它左右两个区间和嘛……
【你讲得出来道理吗就瞎搞】
错解2
我觉得1系列可能做不出来了
于是想到了2系列,我们记录一个区间被覆盖的长度,ans+最后根的长度的变化值【显得比较有道理了】
然而我是怎么写的……【自己都不忍心看】
维护一个len不断加上压进来的线段
【那样遇到连个重合的底边线段你难道不是随时就原地爆炸吗】
错解2.4
那我再维护一个cover,算这个线段有没有被覆盖,被覆盖就加上这个区间的长度
为啥是0……
哦还要加上左右两边的的区间长度
然后还是不对
错解2.47
怎么就不对呢……然后我翻了翻hzwer神犇矩形面积求并的代码
他好像没有维护lazy啊……
然后经过一番奇奇怪怪的思索
我好像有点理解我自己奇怪的算法为什么错了
【我这个代码不止维护了lazy还加了一句异常奇怪的cover=左右两边区间覆盖取个min】
维护lazy应该是没有什么问题的,但是这就相当于把一个大线段拆小,再复原
后面一句应该是因为这相当与把线段合并成一个大的,也没什么意义
两个一起上就有奇怪的化学反应?
所以正解3
压线段进树的正确姿势是维护一个cover记录压的层数,删除线段在对应的cover删除层数,然后记录一下这个区间总共的线段长度
最后维护到根就是我们想要的当前线段并
然后又有很多奇奇怪怪的问题
……例如数组越界导致的WA
/*
ID: ivorysi
LANG: C++
PROG: picture
*/
#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define siji(i,x,y) for(int i=(x);i<=(y);++i)
#define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
#define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
#define sigongzi(j,x,y) for(int j=(x);j>(y);--j)
#define inf 0x5f5f5f5f
#define ivorysi
#define mo 97797977
#define hash 974711
#define base 47
#define fi first
#define se second
#define pii pair<int,int>
#define esp 1e-8
typedef long long ll;
using namespace std;
struct node {
int s,t,y,on;
node (int st=, int ed=, int ceng=, int num=) {//@要写上初值
s=st;t=ed;y=ceng;on=num;
}
bool operator <(const node &b) const {
return y<b.y || (y==b.y && on>b.on);
}
}seg[];
struct data {
int l,r,len,cover;
}tree[];
int n;
int lx[],rx[],ly[],ry[],ans;
void maketree(int u,int l,int r) {
tree[u].l=l;tree[u].r=r;
tree[u].len=tree[u].cover=;
if(l==r) {
return;
}
int mid=(l+r)>>;
maketree(u<<,l,mid);
maketree(u<<|,mid+,r);
}
void check(int u) {
if(tree[u].cover>) tree[u].len=tree[u].r-tree[u].l+;
else if(tree[u].l==tree[u].r) tree[u].len=;
//@少了这句话数组会越界从而导致……WA?开到200000可以解决问题
else tree[u].len=tree[u<<].len+tree[u<<|].len;
}
void change(int u,int x,int y,int c) {
if(x<=tree[u].l && tree[u].r<=y) {
tree[u].cover+=c;
check(u);
//@如果维护lazy:
//@像区间加一样操作,可能覆盖到的地方没有办法及时减掉,因为矩形的边都是成对出现
return;
}
int mid=(tree[u].l+tree[u].r)>>;
if(x<=mid) {change(u<<,x,y,c);}
if(y>mid) {change(u<<|,x,y,c);}
check(u);
}
void solve() {
scanf("%d",&n);
siji(i,,n) {
scanf("%d%d%d%d",&lx[i],&ly[i],&rx[i],&ry[i]);
}
siji(i,,n) {
seg[i*-] = node(lx[i],rx[i],ly[i],);
seg[i*] = node(lx[i],rx[i],ry[i],-);
}
sort(seg+,seg+*n+);
maketree(,-,);//@其实如果是浮点数就需要hash了,然而并不需要
siji(i,,*n) {
int temp=tree[].len;
change(,seg[i].s,seg[i].t-,seg[i].on);
ans+=abs(temp-tree[].len);
}
siji(i,,n) {
seg[i*-] = node(ly[i],ry[i],lx[i],);
seg[i*] = node(ly[i],ry[i],rx[i],-);
}
sort(seg+,seg+*n+);
maketree(,-,);
siji(i,,*n) {
int temp=tree[].len;
change(,seg[i].s,seg[i].t-,seg[i].on);
ans+=abs(temp-tree[].len);
}
printf("%d\n",ans);
}
int main(int argc, char const *argv[])
{
#ifdef ivorysi
freopen("picture.in","r",stdin);
freopen("picture.out","w",stdout);
#else
freopen("f1.in","r",stdin);
#endif
solve();
return ;
}
USACO 5.5 Picture的更多相关文章
- USACO 5.5 Picture(周长并)
POJ最近做过的原题. /* ID: cuizhe LANG: C++ TASK: picture */ #include <cstdio> #include <cstring> ...
- USACO 4.4 Frame Up
Frame Up Consider the following five picture frames shown on an 9 x 8 array: ........ ........ ..... ...
- USACO 5.5 章节
Picture 题目大意 IOI 1998 求n (<=5000)个矩形 覆盖的图形 的周长(包括洞), 坐标范围[-10000,10000] 题解 一眼离散化+2维线段树,但仔细一想 空间不太 ...
- USACO . Your Ride Is Here
Your Ride Is Here It is a well-known fact that behind every good comet is a UFO. These UFOs often co ...
- 【USACO 3.1】Stamps (完全背包)
题意:给你n种价值不同的邮票,最大的不超过10000元,一次最多贴k张,求1到多少都能被表示出来?n≤50,k≤200. 题解:dp[i]表示i元最少可以用几张邮票表示,那么对于价值a的邮票,可以推出 ...
- USACO翻译:USACO 2013 NOV Silver三题
USACO 2013 NOV SILVER 一.题目概览 中文题目名称 未有的奶牛 拥挤的奶牛 弹簧牛 英文题目名称 nocow crowded pogocow 可执行文件名 nocow crowde ...
- USACO翻译:USACO 2013 DEC Silver三题
USACO 2013 DEC SILVER 一.题目概览 中文题目名称 挤奶调度 农场航线 贝西洗牌 英文题目名称 msched vacation shuffle 可执行文件名 msched vaca ...
- USACO翻译:USACO 2014 DEC Silver三题
USACO 2014 DEC SILVER 一.题目概览 中文题目名称 回程 马拉松 奶牛慢跑 英文题目名称 piggyback marathon cowjog 可执行文件名 piggyback ma ...
- USACO翻译:USACO 2012 FEB Silver三题
USACO 2012 FEB SILVER 一.题目概览 中文题目名称 矩形草地 奶牛IDs 搬家 英文题目名称 planting cowids relocate 可执行文件名 planting co ...
随机推荐
- Hadoop生态圈-注册并加载协处理器(coprocessor)的三种方式
Hadoop生态圈-注册并加载协处理器(coprocessor)的三种方式 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 到目前为止,大家已经掌握了如何使用过滤器来减少服务器端通过 ...
- SQL语句(十八_补充)——存储过程
一. 变量 1. 形式: @x (局部), @@x(全局) 2. 定义: declare @x 3. 赋值:Set @x = ? 4. 作用: 通用化 存储在服务器 5. 存储过程(预编译过的T-SQ ...
- 《设计模式》-原则二:里氏代换原则(LSP)
回顾一下上一节说的“开闭原则” 说的是 一个软件要遵循对修改关闭 对新功能扩展的原则. 这一次来说说 “里氏代换原则” 意思是说:子类型必须能代替他们的基类. 看了半天的例子 好像 是懂非懂啊...相 ...
- 【BZOJ】2655: calc 动态规划+拉格朗日插值
[题意]一个序列$a_1,...,a_n$合法当且仅当它们都是[1,A]中的数字且互不相同,一个序列的价值定义为数字的乘积,求所有序列的价值和.n<=500,A<=10^9,n+1< ...
- 【Linux 命令】 rsync 目录覆盖软链接,保持软链接不变并同步目录内容
需求:有两个相同文件名的目录需要使用其中一个目录覆盖另外一个 问题: 被覆盖目录下存在软链接,但在源目录下软链接是一个目录 需要解决的方案: 要求将原目录里和被覆盖目录里冲突的目录文件复制到B的软链 ...
- vue_router 动态路由
配置子路由: 路由的视图都需要使用view-router 子路由也可以嵌套路由使用: children来做嵌套如上图 使用location.页面name就可以做页面跳转 mounted:挂载,延迟跳转 ...
- 网络流建图(典型)(EK)
题目链接:https://cn.vjudge.net/contest/68128#problem/B 具体思路: 按照 源点 - > 食物 - > 牛1 - > 牛2 - > ...
- Codeforces Round #504 D. Array Restoration
Codeforces Round #504 D. Array Restoration 题目描述:有一个长度为\(n\)的序列\(a\),有\(q\)次操作,第\(i\)次选择一个区间,将区间里的数全部 ...
- 数据库——mysql如何获取当前时间
1.1 获得当前日期+时间(date + time)函数:now() 除了 now() 函数能获得当前的日期时间外,MySQL 中还有下面的函数: current_timestamp() curren ...
- Flask:静态文件&模板(0.1)
Windows 10家庭中文版,Python 3.6.4,Flask 1.0.2 前面看了Flask的Quickstart文档,可是,一直没有练习里面的内容,这不,刚刚练习完毕,来写篇博文记录一下! ...