hdu1828 (Picture) &poj 1177( Picture)&sdibt 2390(5.5.1 Picture 矩形周长)(线段树+扫描)

题目地址:hdu1828 (Picture)  & poj 1177( Picture) & sdibt 2390(5.5.1 Picture 矩形周长)

 

题目大意:

    给你N个矩形,求出N个矩形构成的周长。

 

解题思路:

     线段数+扫描线。

推荐博客: POJ1177 Picture(线段树求轮廓周长)

               POJ 1177 Picture (线段树+离散化+扫描线) 详解

注意事项:

   该题在求面积的基础上有了升级,多写了一个被调需要求出投影与Y轴有几段,不然样例会少算20,就是给出图形中间的小矩形的上下边没有计算在内。

   考虑重边,虽然hdu和poj不考虑也能过,但是sdibt过不了。

重边测试数据:

/*
2
-10 -10 0 10
0 -10 10 10
输出:80
不考虑的话会输出:120 */

 

代码:

  1 #include <algorithm>
  2 #include <iostream>
  3 #include <sstream>
  4 #include <cstdlib>
  5 #include <cstring>
  6 #include <cstdio>
  7 #include <string>
  8 #include <bitset>
  9 #include <vector>
 10 #include <queue>
 11 #include <stack>
 12 #include <cmath>
 13 #include <list>
 14 #include <map>
 15 #include <set>
 16 using namespace std;
 17 /***************************************/
 18 #define ll long long
 19 #define int64 __int64
 20 /***************************************/
 21 const int INF = 0x7f7f7f7f;
 22 const double eps = 1e-8;
 23 const double PIE=acos(-1.0);
 24 const int d1x[]= {0,-1,0,1};
 25 const int d1y[]= {-1,0,1,0};
 26 const int d2x[]= {0,-1,0,1};
 27 const int d2y[]= {1,0,-1,0};
 28 const int fx[]= {-1,-1,-1,0,0,1,1,1};
 29 const int fy[]= {-1,0,1,-1,1,-1,0,1};
 30 /***************************************/
 31 void openfile()
 32 {
 33     freopen("data.in","rb",stdin);
 34     freopen("data.out","wb",stdout);
 35 }
 36 /**********************华丽丽的分割线,以上为模板部分*****************/
 37 const int M=10000;
 38 
 39 struct tree
 40 {
 41     int left,right;//左右区间
 42     double turel,turer,cnt;//记录左右区间的真实值和 投影Y轴坐标的覆盖的程度cnt
 43     int lbd,rbd;  //辅助求投影Y轴有几段
 44     int setline;  //记录投影Y轴有几段,假如[1,2][4,5]覆盖在Y轴
 45                  //说明有两段覆盖在Y轴所以该周长应该是nowline+2(Setline)*2*(line[i].x-line[i-1].x)
 46     int c; //记录该区间被覆盖几次。
 47 
 48 } node[M*4];
 49 struct Line
 50 {
 51     double x,y1,y2; //记录每一条扫描线
 52     int f;//标记入边1,出边为-1
 53 } line[M];//储存所有的线段
 54 int cnt;
 55 double y[M];//将y的坐标记录然后离散化
 56 bool cmp(Line a,Line b)//排序 
 57 {
 58     if (a.x==b.x)  //这句需要有做完该题你会发现有重边的样例过不去,
 59                    //排序的时候若X某条出边和某条坐标相等将入边排在前面就能解决重边的问题。
 60         return a.f>b.f;
 61     return a.x<b.x;
 62 }
 63 void build__tree(int id,int l,int r)//初始化树
 64 {
 65     int mid=(l+r)/2;
 66     node[id].turel=y[l];
 67     node[id].turer=y[r];
 68     node[id].left=l;
 69     node[id].right=r;
 70     node[id].cnt=0;
 71     node[id].c=0;
 72     node[id].lbd=0;
 73     node[id].rbd=0;
 74     node[id].setline=0;
 75     if (l+1==r)
 76         return ;
 77     build__tree(id*2,l,mid);
 78     build__tree(id*2+1,mid,r);
 79 }
 80 //更新line
 81 void upline(int i)
 82 {
 83     if (node[i].c>0)
 84     {
 85         node[i].lbd=1;
 86         node[i].rbd=1;
 87         node[i].setline=1;
 88     }
 89     else if (node[i].right-node[i].left == 1)
 90     {
 91         node[i].lbd = 0;
 92         node[i].rbd = 0;
 93         node[i].setline = 0;
 94     }
 95     else
 96     {
 97         node[i].lbd = node[2*i].lbd;
 98         node[i].rbd = node[2*i+1].rbd;
 99         node[i].setline = node[2*i].setline+node[2*i+1].setline-node[2*i].rbd*node[2*i+1].lbd;
100     }
101 }
102 //更新投影Y轴的线段
103 void upcnt(int id)
104 {
105     if (node[id].c>0)
106     {
107         node[id].cnt=node[id].turer-node[id].turel;
108         return ;
109     }
110     if (node[id].left+1==node[id].right)
111         node[id].cnt=0;
112     else
113         node[id].cnt=node[id*2].cnt+node[id*2+1].cnt;
114 }
115 void updata(int id,Line v)
116 {
117     if (node[id].turel==v.y1&&node[id].turer==v.y2)
118     {
119         node[id].c+=v.f;
120         upcnt(id);
121         upline(id);
122         return ;
123     }
124     if (v.y2<=node[id*2].turer)
125         updata(id*2,v);
126     else if (v.y1>=node[id*2+1].turel)
127         updata(id*2+1,v);
128     else
129     {
130         Line tmp;
131         tmp=v;
132         tmp.y2=node[id*2].turer;
133         updata(id*2,tmp);
134         tmp=v;
135         tmp.y1=node[id*2+1].turel;
136         updata(id*2+1,tmp);
137     }
138     upcnt(id);
139     upline(id);
140 }
141 int main()
142 {
143     int n;
144     scanf("%d",&n);
145     int i,j;
146     int d=1;
147     for(i=1; i<=n; i++)
148     {
149         double x1,x2,y1,y2;
150         scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
151         line[d].x=x1;
152         line[d].y1=y1;
153         line[d].y2=y2;
154         line[d].f=1;
155         y[d]=y1;
156         d++;
157         line[d].x=x2;
158         line[d].y1=y1;
159         line[d].y2=y2;
160         line[d].f=-1;
161         y[d]=y2;
162         d++;
163     }
164     sort(y+1,y+d);
165     sort(line+1,line+d,cmp);
166     int ncount=unique(y+1,y+d)-(y+1); //去重。
167     build__tree(1,1,ncount);
168     updata(1,line[1]);
169     double sum=0;
170     double ce=0;
171     double nowline=0;
172     int Setline=0;
173     for(i=2; i<d; i++)
174     {
175         Setline=node[1].setline;
176         nowline=node[1].cnt-ce;
177         if (nowline<0)
178             nowline=-nowline;
179         if (node[1].cnt==0)
180         {
181             sum+=(line[i-1].y2-line[i-1].y1);
182             ce=0;
183             nowline=0;
184         }
185         else
186             sum+=nowline+Setline*2*(line[i].x-line[i-1].x);
187         ce=node[1].cnt;
188         updata(1,line[i]);
189     }
190     sum+=(line[i-1].y2-line[i-1].y1);
191     printf("%.0f\n",sum);
192     return 0;
193 }
194 /*
195 4
196 5 5 20 10
197 10 0 15 15
198 5 5 30 10
199 27 8 35 15
200 
201 2
202 -10 -10 0 10
203 0 -10 10 10
204 */
View Code

 

posted @ 2014-11-12 21:20  kinghold  Views(237)  Comments(0Edit  收藏  举报