[线段树扫描线][USACO5.5]矩形周长Picture

墙上贴着许多形状相同的海报、照片。它们的边都是水平和垂直的。每个矩形图片可能部分或全部的覆盖了其他图片。所有矩形合并后的边长称为周长。

所有矩形的边界。所有矩形顶点的坐标都是整数。

输入文件的第一行是一个整数N(0<=N<5000),表示有多少个矩形。接下来N行给出了每一个矩形左下角坐标和右上角坐标(所有坐标的数值范围都在-10000到10000之间)。

输出文件只有一个正整数,表示所有矩形的周长。

题解

线段树扫描线  https://www.luogu.org/problemnew/solution/P1856

维护的东西非常巧妙  注意覆盖标记不下传  因为只查询根节点

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N=10000+5;
 6 int n;
 7 struct edge{int x,y,h,c;}a[N];
 8 bool cmp(edge p,edge q) {return p.h<q.h || (p.h==q.h&& p.c>q.c);}
 9
10 int tot,b[N];
11 inline int hehe(int x) {return lower_bound(b+1,b+tot+1,x)-b;}
12
13 struct point{int l,r,cov,cnt,len; bool lf,rf; }t[4*N];
14 inline void pushup(int i,int l,int r)
15  {if(t[i].cov)
16      {t[i].len=t[i].r-t[i].l;
17       t[i].lf=t[i].rf=1;
18       t[i].cnt=1;
19      }
20   else
21      {t[i].len=t[2*i].len+t[2*i+1].len;
22       t[i].lf=t[2*i].lf; t[i].rf=t[2*i+1].rf;
23       t[i].cnt=t[2*i].cnt+t[2*i+1].cnt;
24       if(t[2*i].rf && t[2*i+1].lf) t[i].cnt--;
25      }
26  }
27 void build(int i,int l,int r)
28  {t[i].l=b[l]; t[i].r=b[r+1];
29   if(l==r) return;
30   int mid=l+r>>1;
31   build(2*i,l,mid); build(2*i+1,mid+1,r);
32  }
33 void change(int i,int l,int r,int p,int q,int v)
34  {if(p<=l && r<=q) {t[i].cov+=v; pushup(i,l,r); return;}
35   int mid=l+r>>1;
36   if(p<=mid) change(2*i,  l,  mid,p,q,v);
37   if(mid<q)     change(2*i+1,mid+1,r,p,q,v);
38   pushup(i,l,r);
39  }
40 int main()
41 {
42  scanf("%d",&n); int x1,y1,x2,y2;
43
44  for(int i=1;i<=n;i++)
45   { scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
46     a[2*i-1].x=a[2*i].x=x1; a[2*i-1].y=a[2*i].y=x2;
47     a[2*i-1].h=y1; a[2*i].h=y2;
48     a[2*i-1].c=1;  a[2*i].c=-1;
49     b[++tot]=x1; b[++tot]=x2;
50   }
51  sort(a+1,a+2*n+1,cmp);
52
53  sort(b+1,b+tot+1); tot=unique(b+1,b+tot+1)-b-1;
54
55  build(1,1,tot-1); int ans=0,last=0;
56
57  for(int i=1;i<=2*n;i++)
58   { change(1,1,tot-1,hehe(a[i].x),hehe(a[i].y)-1,a[i].c);
59
60       ans+=2*t[1].cnt*(a[i+1].h-a[i].h)+abs(t[1].len-last);
61       last=t[1].len;
62   }
63  printf("%d\n",ans);
64 return 0;
65 }

原文地址:https://www.cnblogs.com/YuXiaoze/p/11420758.html

时间: 2024-10-11 22:36:54

[线段树扫描线][USACO5.5]矩形周长Picture的相关文章

USACO5.5 矩形周长 Picture | 扫描线 + 线段树

题目:Luogu 1856 扫描线,将矩形拆成两条边分别为 +1 和 -1,计算无重叠部分的长度. 由于 update 区间 [a, b] 和 [b, c] 时会把 b 加两次,所以统一转换成 [a,b),累加长度的时候再将右端点右移. 需要注意,在覆盖一条边时,不能直接累加边的长度,像下图: 在覆盖边 [1,4] 前,[3,4] 已经累加过了,所以此时应该累计的是 [1,4] 的长度减去已经覆盖过的长度,然后再把 [1,4] 覆盖上: 相应的,在删除 [1,4] 这条边时,累计的是删除 [1,

[USACO5.5]矩形周长Picture[扫描线+线段树]

题意:给出一些矩阵,求这些矩阵合并后外部(被包括在内部的不算)周长 端点-1这个是用点代替了边,区间内有几个点就代表区间长度是多少 #include <bits/stdc++.h> using namespace std; const int inf = 0x3f3f3f3f; inline void chmax(int &x, int y) {if (x < y) x = y;} inline void chmin(int &x, int y) {if (x >

luogu P1856 [USACO5.5]矩形周长Picture 扫描线 + 线段树

Code: #include<bits/stdc++.h> #define maxn 200007 #define inf 100005 using namespace std; void setIO(string s) { string in=s+".in"; freopen(in.c_str(),"r",stdin); } struct Edge { int l,r,h,flag; }edges[maxn]; int n; namespace tr

[USACO5.5] 矩形周长Picture

https://www.luogu.org/problemnew/show/P1856 1.每个矩形由两条横向边和两条纵向边组成. 2.对于横向边,按纵坐标排序.设当前讨论的边为 A [s , t] 如果 A 是某个矩形的靠下的边,在树中查询[s,t]区间中被覆盖的长度为x,那么加上这条边后将增加(t-s-x); 如果 A 是某个矩形的靠上的边,先删除它的对应边,再在树中查询[s,t]区间中被覆盖的长度为x,那么加上这条边后将增加(t-s-x); 3.对于纵向边,按横坐标排序,讨论方法与横向边相

线段树扫描线

扫描线一般运用在图形上面,它和它的字面意思十分相似,就是一条线在整个图上扫来扫去,它一般被用来解决图形面积,周长等问题. -------OI Wiki 扫描线求面积并 P5490 [模板]扫描线 如图,假设三个矩形,求其并集的面积.考虑将每个矩形处理成两条平行于 y 轴的线段,左边的线段标记为 +1 ,右边的线段标记为 -1 ,用一个四元组\((x, y_1, y_2, k)\)存下来,于是我们得到了这样一个图形: 按照四元组中 x 坐标由小到大排序,我们就可以分成一段一段地处理整个图形: 不同

hdu 1828 Picture(线段树&amp;扫描线&amp;周长并)

Picture Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2578    Accepted Submission(s): 1363 Problem Description A number of rectangular posters, photographs and other pictures of the same shap

HDU 1828 Picture 线段树+扫描线

题意:给你一些矩形的左上角点的坐标和右下角点的坐标,求周长并 最显而易见的思路就是对于x轴和y轴做两次扫描线,对于负数的坐标进行离散化.每次增加的值是线段变化量的绝对值.具体写法和求面积并的差不多. #include <cstdio> #include <algorithm> #include <cstring> #include <vector> using namespace std; #define lson rt << 1 , l , m

poj 3277 City Horizon (线段树 扫描线 矩形面积并)

题目链接 题意: 给一些矩形,给出长和高,其中长是用区间的形式给出的,有些区间有重叠,最后求所有矩形的面积. 分析: 给的区间的范围很大,所以需要离散化,还需要把y坐标去重,不过我试了一下不去重 也不会出错, 所有的区间都能列出来,只是在查找的时候费点事. 给的矩形相当于在同一水平线上的,也就是y1坐标相当于为0,其他的就和 poj 1151 Atlantis 差不多了. 我写的思路是按照矩形面积并的思路写的: 但是还有另一种方法也是挺简单的,就是把给的矩形按照高从小到大排序,然后依次插入线段树

HDU 1264 Counting Squares (线段树-扫描线-矩形面积并)

Problem A : Counting Squares From:HDU, 1264 Problem Description Your input is a series of rectangles, one per line. Each rectangle is specified as two points(X,Y) that specify the opposite corners of a rectangle. All coordinates will be integers in t