HDU 1542 传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1542
题目大意就是几个矩形相交,然后求出总的覆盖面积,覆盖多次的按一次算。典型的面积并问题。
大体思路:
记录所给的点,排序,去掉重复的点,对点编号,可以理解成存放点的数组的下表即为编号。
对Y轴建立线段树,利用线段树计算面积。
AC_code:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 #include <cstdlib> 6 7 using namespace std; 8 9 double x[2200],y[2200]; 10 11 double st[2200][8000]; 12 13 struct N1 14 { 15 double x1,x2,y1,y2; 16 }a[1100]; 17 18 int del(double *t,int n)// 去掉重复点的函数 19 { 20 double s[2200]; 21 int top = 0,i; 22 for(i = 0;i < n; i++) 23 { 24 if(top == 0) 25 { 26 s[top++] = t[i]; 27 } 28 else if(t[i] != s[top-1]) 29 { 30 s[top++] = t[i]; 31 } 32 } 33 for(i = 0;i < top; i++) 34 { 35 t[i] = s[i]; 36 } 37 return top; 38 } 39 40 int check_site(double *t,int s,int e,double x)//二分查找当前点的对应编号 41 { 42 if(s == e) 43 return s; 44 int m = (s+e)/2; 45 if(x == t[m]) 46 return m; 47 if(x < t[m]) 48 return check_site(t,s,m-1,x); 49 else return check_site(t,m+1,e,x); 50 } 51 52 double change(double *st,int l,int r,int node,int ml,int mr,int site)//对线段树更新 53 { 54 if(ml == l && mr == r && ml+1 == mr) 55 { 56 double area = (y[site+1] - y[site]) * (x[r] - x[l]); 57 58 if(area > st[node]) 59 { 60 double temp = area - st[node]; 61 st[node] = area; 62 return (temp); 63 } 64 else return 0; 65 } 66 67 int m = (l+r)/2; 68 69 if(mr <= m) 70 { 71 double area = change(st,l,m,node+node,ml,mr,site); 72 st[node] += area; 73 return area; 74 } 75 if(m <= ml) 76 { 77 double area = change(st,m,r,node+node+1,ml,mr,site); 78 st[node] += area; 79 return area; 80 } 81 82 double area = change(st,l,m,node+node,ml,m,site)+change(st,m,r,node+node+1,m,mr,site); 83 st[node] += area; 84 return area; 85 } 86 87 int main() 88 { 89 int n,icase = 1; 90 int i,j; 91 double area; 92 93 while(cin>>n && n) 94 { 95 for(i = 0,j = 0; i < n; i++) 96 { 97 cin>>a[i].x1>>a[i].y1>>a[i].x2>>a[i].y2; 98 x[j] = a[i].x1; 99 y[j] = a[i].y1; 100 j++; 101 x[j] = a[i].x2; 102 y[j] = a[i].y2; 103 j++; 104 } 105 106 sort(x,x+j); 107 int sx = del(x,j); 108 sort(y,y+j); 109 int sy = del(y,j);//排序去掉重复点 110 111 for(i = 0;i <= sy; i++)//初始化线段树 112 { 113 memset(st[i],0,sizeof(st[i])); 114 } 115 116 for(area = 0,i = 0;i < n; i++) 117 { 118 int site_x1 = check_site(x,0,sx-1,a[i].x1);//查找对应编号 119 int site_y1 = check_site(y,0,sy-1,a[i].y1); 120 int site_x2 = check_site(x,0,sx-1,a[i].x2); 121 int site_y2 = check_site(y,0,sy-1,a[i].y2); 122 123 int temp; 124 if(site_x1 > site_x2) 125 { 126 temp = site_x1; 127 site_x1 = site_x2; 128 site_x2 = temp; 129 } 130 131 if(site_y1 > site_y2) 132 { 133 temp = site_y1; 134 site_y1 = site_y2; 135 site_y2 = temp; 136 } 137 138 for(j = site_y1;j < site_y2; j++)//每一棵线段树的第一个节点即为该段区域内的面积 139 { 140 area += change(st[j],0,sx-1,1,site_x1,site_x2,j);//area记录总面积 141 } 142 } 143 144 printf("Test case #%d\n",icase++); 145 printf("Total explored area: %.2lf\n\n",area); 146 } 147 return 0; 148 }
换成这种矩阵模拟的办法也能过 时间和内存都有所减少 瞬间感觉自己丝毫没有窥探到线段树的精髓……sad
矩阵模拟的AC_code:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 #include <cstdlib> 6 7 using namespace std; 8 9 double x[2200],y[2200]; 10 11 double st[2200][8000]; 12 13 struct N1 14 { 15 double x1,x2,y1,y2; 16 }a[1100]; 17 18 int del(double *t,int n)// 去掉重复点的函数 19 { 20 double s[2200]; 21 int top = 0,i; 22 for(i = 0;i < n; i++) 23 { 24 if(top == 0) 25 { 26 s[top++] = t[i]; 27 } 28 else if(t[i] != s[top-1]) 29 { 30 s[top++] = t[i]; 31 } 32 } 33 for(i = 0;i < top; i++) 34 { 35 t[i] = s[i]; 36 } 37 return top; 38 } 39 40 int check_site(double *t,int s,int e,double x)//二分查找当前点的对应编号 41 { 42 if(s == e) 43 return s; 44 int m = (s+e)/2; 45 if(x == t[m]) 46 return m; 47 if(x < t[m]) 48 return check_site(t,s,m-1,x); 49 else return check_site(t,m+1,e,x); 50 } 51 52 /*double change(double *st,int l,int r,int node,int ml,int mr,int site)//对线段树更新 53 { 54 if(ml == l && mr == r && ml+1 == mr) 55 { 56 double area = (y[site+1] - y[site]) * (x[r] - x[l]); 57 58 if(area > st[node]) 59 { 60 double temp = area - st[node]; 61 st[node] = area; 62 return (temp); 63 } 64 else return 0; 65 } 66 67 int m = (l+r)/2; 68 69 if(mr <= m) 70 { 71 double area = change(st,l,m,node+node,ml,mr,site); 72 st[node] += area; 73 return area; 74 } 75 if(m <= ml) 76 { 77 double area = change(st,m,r,node+node+1,ml,mr,site); 78 st[node] += area; 79 return area; 80 } 81 82 double area = change(st,l,m,node+node,ml,m,site)+change(st,m,r,node+node+1,m,mr,site); 83 st[node] += area; 84 return area; 85 }*/ 86 87 double change(int x1,int x2,int y1,int y2) 88 { 89 int i,j; 90 double area = 0; 91 for(i = y1;i < y2; i++) 92 { 93 for(j = x1;j < x2; j++) 94 { 95 if(st[i][j] == 0) 96 { 97 st[i][j] = (x[j+1]-x[j]) * (y[i+1]-y[i]); 98 area += st[i][j]; 99 } 100 } 101 } 102 return area; 103 } 104 105 int main() 106 { 107 int n,icase = 1; 108 int i,j; 109 double area; 110 111 while(cin>>n && n) 112 { 113 for(i = 0,j = 0; i < n; i++) 114 { 115 cin>>a[i].x1>>a[i].y1>>a[i].x2>>a[i].y2; 116 x[j] = a[i].x1; 117 y[j] = a[i].y1; 118 j++; 119 x[j] = a[i].x2; 120 y[j] = a[i].y2; 121 j++; 122 } 123 124 sort(x,x+j); 125 int sx = del(x,j); 126 sort(y,y+j); 127 int sy = del(y,j);//排序去掉重复点 128 129 for(i = 0;i <= sy; i++)//初始化线段树 130 { 131 memset(st[i],0,sizeof(st[i])); 132 } 133 134 for(area = 0,i = 0;i < n; i++) 135 { 136 int site_x1 = check_site(x,0,sx-1,a[i].x1);//查找对应编号 137 int site_y1 = check_site(y,0,sy-1,a[i].y1); 138 int site_x2 = check_site(x,0,sx-1,a[i].x2); 139 int site_y2 = check_site(y,0,sy-1,a[i].y2); 140 141 int temp; 142 if(site_x1 > site_x2) 143 { 144 temp = site_x1; 145 site_x1 = site_x2; 146 site_x2 = temp; 147 } 148 149 if(site_y1 > site_y2) 150 { 151 temp = site_y1; 152 site_y1 = site_y2; 153 site_y2 = temp; 154 } 155 156 area += change(site_x1,site_x2,site_y1,site_y2); 157 158 /*for(j = site_y1;j < site_y2; j++)//每一棵线段树的第一个节点即为该段区域内的面积 159 { 160 area += change(st[j],0,sx-1,1,site_x1,site_x2,j);//area记录总面积 161 }*/ 162 } 163 164 printf("Test case #%d\n",icase++); 165 printf("Total explored area: %.2lf\n\n",area); 166 } 167 return 0; 168 }