【HDOJ1828&&POJ1177】Picture(线段树,扫描线)

题意:给定n个矩形,求他们的并的周长

n<=5e3,abs(x[i])<=1e4

思路:From https://www.cnblogs.com/kuangbin/archive/2013/04/10/3013437.html

真实“线段”树

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<string>
  4 #include<cmath>
  5 #include<iostream>
  6 #include<algorithm>
  7 #include<map>
  8 #include<set>
  9 #include<queue>
 10 #include<vector>
 11 using namespace std;
 12 typedef long long ll;
 13 typedef unsigned int uint;
 14 typedef unsigned long long ull;
 15 typedef pair<int,int> PII;
 16 typedef vector<int> VI;
 17 #define fi first
 18 #define se second
 19 #define MP make_pair
 20 #define N   11000
 21 #define M   7010
 22 #define eps 1e-8
 23 #define pi  acos(-1)
 24 #define oo  1e9
 25 #define MOD 10007
 26
 27 struct node
 28 {
 29     int l,r,cnt,num,c;
 30     bool lc,rc;
 31 }t[N<<2];
 32
 33 struct Line
 34 {
 35     int x1,x2,y,f;
 36 }line[N];
 37
 38 bool cmp(Line a,Line b)
 39 {
 40     return a.y<b.y;
 41 }
 42
 43 int x[N];
 44
 45 void build(int l,int r,int p)
 46 {
 47     t[p].l=x[l];
 48     t[p].r=x[r];
 49     t[p].cnt=t[p].num=t[p].c=0;
 50     t[p].lc=t[p].rc=false;
 51     if(l+1==r) return;
 52     int mid=(l+r)>>1;
 53     build(l,mid,p<<1);
 54     build(mid,r,p<<1|1);
 55 }
 56
 57 void calc(int p)
 58 {
 59     if(t[p].c>0)
 60     {
 61         t[p].cnt=t[p].r-t[p].l;
 62         t[p].num=1;
 63         t[p].lc=t[p].rc=true;
 64         return;
 65     }
 66     if(t[p].l+1==t[p].r)
 67     {
 68         t[p].cnt=t[p].num=0;
 69         t[p].lc=t[p].rc=false;
 70     }
 71      else
 72      {
 73          t[p].cnt=t[p<<1].cnt+t[p<<1|1].cnt;
 74          t[p].lc=t[p<<1].lc;
 75          t[p].rc=t[p<<1|1].rc;
 76          t[p].num=t[p<<1].num+t[p<<1|1].num;
 77          if(t[p<<1].rc&&t[p<<1|1].lc) t[p].num--;
 78      }
 79 }
 80
 81 void update(int l,int r,Line e,int p)
 82 {
 83     if(t[p].l==e.x1&&t[p].r==e.x2)
 84     {
 85         t[p].c+=e.f;
 86         calc(p);
 87         return;
 88     }
 89     int mid=(l+r)>>1;
 90     if(e.x2<=t[p<<1].r) update(l,mid,e,p<<1);
 91      else if(e.x1>=t[p<<1|1].l) update(mid,r,e,p<<1|1);
 92       else
 93       {
 94           Line tmp=e;
 95           tmp.x2=t[p<<1].r;
 96           update(l,mid,tmp,p<<1);
 97           tmp=e;
 98           tmp.x1=t[p<<1|1].l;
 99           update(mid,r,tmp,p<<1|1);
100       }
101     calc(p);
102 }
103
104 int main()
105 {
106     //freopen("poj1177.in","r",stdin);
107     //freopen("poj1177.out","w",stdout);
108     int n;
109     while(scanf("%d",&n)!=EOF)
110     {
111         int cnt=0;
112         for(int i=0;i<=n-1;i++)
113         {
114             int x1,y1,x2,y2;
115             scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
116             line[cnt].x1=x1;
117             line[cnt].x2=x2;
118             line[cnt].y=y1;
119             line[cnt].f=1;
120             x[cnt++]=x1;
121             line[cnt].x1=x1;
122             line[cnt].x2=x2;
123             line[cnt].y=y2;
124             line[cnt].f=-1;
125             x[cnt++]=x2;
126         }
127         sort(line,line+cnt,cmp);
128         sort(x,x+cnt);
129         int m=unique(x,x+cnt)-x;
130         build(0,m-1,1);
131
132         int ans=0;
133         int last=0;
134         for(int i=0;i<cnt-1;i++)
135         {
136             update(0,m-1,line[i],1);
137
138             ans+=t[1].num*2*(line[i+1].y-line[i].y);
139             ans+=abs(t[1].cnt-last);
140             last=t[1].cnt;
141         }
142         update(0,m-1,line[cnt-1],1);
143         ans+=abs(t[1].cnt-last);
144         printf("%d\n",ans);
145     }
146
147
148     return 0;
149 }
150
151     

原文地址:https://www.cnblogs.com/myx12345/p/9863933.html

时间: 2024-11-12 13:56:47

【HDOJ1828&&POJ1177】Picture(线段树,扫描线)的相关文章

HDU 1828 Picture 线段树+扫描线

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

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

hdu1828 Picture (线段树:扫描线周长)

依然是扫描线,只不过是求所有矩形覆盖之后形成的图形的周长. 容易发现,扫描线中的某一条横边对答案的贡献. 其实就是 加上/去掉这条边之前的答案 和 加上/去掉这条边之后的答案 之差的绝对值 然后横着竖着都做一遍就行了 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define N 10010 5 #define ll long long 6 using namespace std;

hdu1828 Picture(线段树+离散化+扫描线)两种方法

C - Picture Time Limit:2000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u Submit Status Description A number of rectangular posters, photographs and other pictures of the same shape are pasted on a wall. Their sides are all vertical or

POJ 1177/HDU 1828 picture 线段树+离散化+扫描线 轮廓周长计算

求n个图矩形放下来,有的重合有些重合一部分有些没重合,求最后总的不规则图型的轮廓长度. 我的做法是对x进行一遍扫描线,再对y做一遍同样的扫描线,相加即可.因为最后的轮廓必定是由不重合的线段长度组成的,这样理论上是对的 要注意处理高度相同的线段,把底边优先处理(在代码里就是f标记为1的线段),因为若是一个矩形的底边和另一个矩形的上边重合,则这个轮廓肯定不能算 不过POJ和HDU的数据好像都比较弱,我没进行上面的细节处理也AC了,不过一个很简单的数据就会不对,所以还是要处理一下才是真正正确的代码 我

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

墙上贴着许多形状相同的海报.照片.它们的边都是水平和垂直的.每个矩形图片可能部分或全部的覆盖了其他图片.所有矩形合并后的边长称为周长. 所有矩形的边界.所有矩形顶点的坐标都是整数. 输入文件的第一行是一个整数N(0<=N<5000),表示有多少个矩形.接下来N行给出了每一个矩形左下角坐标和右上角坐标(所有坐标的数值范围都在-10000到10000之间). 输出文件只有一个正整数,表示所有矩形的周长. 题解 线段树扫描线  https://www.luogu.org/problemnew/sol

【BZOJ】1382: [Baltic2001]Mars Maps (线段树+扫描线)

1382: [Baltic2001]Mars Maps Time Limit: 5 Sec  Memory Limit: 64 MB Description 给出N个矩形,N<=10000.其坐标不超过10^9.求其面积并 Input 先给出一个数字N,代表有N个矩形. 接下来N行,每行四个数,代表矩形的坐标. Output 输出面积并 Sample Input 2 10 10 20 20 15 15 25 30 Sample Output 225 本以为是傻逼题,没想到不容易啊- 线段树+扫描

BZOJ 4059 Cerc2012 Non-boring sequences 线段树+扫描线

题目大意:定义一个序列为[不无聊的]当且仅当这个序列的任意一个区间都存在一个数只出现过一次,给定一个序列,要求判断这个序列是否是[不无聊的] 定义lasti表示第i个元素上一次出现的位置(第一次出现则为0),nexti表示第i个元素下一次出现的位置(最后一次出现则为n+1),那么这个元素能成为某个区间仅出现一次的数,当且仅当这个区间的左端点在[lasti+1,i]之间,右端点在[i,nexti?1]之间 我们可以将区间的左右端点放在二维平面上,那么一个元素产生的贡献是一个矩形,我们要确定的是所有

HDU 4419 Colourful Rectangle --离散化+线段树扫描线

题意: 有三种颜色的矩形n个,不同颜色的矩形重叠会生成不同的颜色,总共有R,G,B,RG,RB,GB,RGB 7种颜色,问7种颜色每种颜色的面积. 解法: 很容易想到线段树扫描线求矩形面积并,但是如何维护每种颜色的长度着实让我伤透了脑筋.后来看了一位朋友的题解,才幡然醒悟. 开始想到了用二进制表示颜色,R用001表示,G用010表示,B用100表示.那么就可以用十进制1~7表示7种不同颜色了. 维护 cov[rt][1~3] 表示此区间内3种原色各有多少个, Len[rt][i]表示每种颜色的长

sgu316Kalevich Strikes Back(线段树+扫描线)

做法:总体想法是求出一个矩形的面积以及它所包含的矩形,然后用自己的面积减掉所包含的.主要问题是怎样求解它所包含的矩形. 因为是没有相交点的,可以利用扫描线的方法去做,类似染色,当前段如果是x色,也就是第x个矩形,那么再把他染成y颜色时,说明x包含y,而当扫到y的上边时,这一段又恢复到x色.标记一下被包含的矩形,记录所包含的矩形. 因为会有恢复染色操作,up需要时时更新,左儿子和右儿子一样颜色时就可以合并为一段. 1 ; 2 } 3 void down(int w) 4 { 5 if(s[w]!=