luogu【P2745】[USACO5.3]窗体面积Window Area
这个题 就是个工程题 (然而一开始我并不知道怎么做。。还是看nocow的。。qwq)(原题入口)
算法为 离散化 + 扫描线 将大坐标变小 并且 用横纵坐标进行扫描 来计算面积
一开始 我想边添加 点的坐标 边 离散 后来发现 有点问题
因为 它离散后的坐标 并不是按顺序来排(因为后来可能还加入中间的点 就需要重新离散)
所以 我就把一开始的操作 和 坐标先存下来 进行离散 再进行操作 (QAQ 搞了好久)
后面 就是计算面积了 把一个大矩形 划分成 许多个小矩形 再进行标记 来计算面积了
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <algorithm> 6 #include <cctype> 7 #include <iostream> 8 #include <map> 9 #include <vector> 10 #define For(i, l, r) for(int i = (l); i <= (int)(r); ++i) 11 #define Fordown(i, r, l) for(int i = (r); i >= (int)(l); --i) 12 #define Set(a, v) memset(a, v, sizeof(a)) 13 #define pb push_back 14 using namespace std; 15 16 inline int read(){ 17 int x = 0, fh = 1; char ch; 18 for(; !isdigit(ch); ch = getchar()) if (ch == '-') fh = -1; 19 for(; isdigit(ch); ch = getchar()) x = (x<<1) + (x<<3) + (ch^'0'); 20 return x * fh; 21 } 22 23 const int N = 2550; 24 map <int, int> fx, fy; //map数组 记录这个坐标是否被离散化过 25 int gx[1<<15], gy[1<<15]; //反向存储标号对应的坐标 26 int cnt_x = 0, cnt_y = 0, cnt = 0; //离散化的个数 27 char id[N]; //记录id数组 28 29 int now_deep = 2*(1<<15), top_deep = (1<<15), back_deep = 3*(1<<15); 30 struct node { 31 int xl, yl, xr, yr; 32 int deep; //层次 33 bool flag; //是否被删除 34 }; 35 node win[N]; //存储窗户 36 37 int idx(char ch) { 38 For (i, 1, cnt) 39 if (id[i] == ch) return i; 40 id[++cnt] = ch; 41 return cnt; 42 } //计算当前l的id 43 44 bool exist[N/2][N/2]; 45 double sum(int num) { 46 if (!win[num].flag) return 0.0000; //如果已经删除 就返回0.0 (好像并没有用) 47 Set(exist, false); //判断小矩形是否存在 48 int sum_area = 0; 49 int now_area = 0; 50 51 For (i, win[num].xl, win[num].xr-1) 52 For (j, win[num].yl, win[num].yr-1) 53 { exist[i][j] = true; //一开始置为真 54 sum_area += fabs ((gx[i+1] - gx[i] ) * (gy[j+1] - gy[j]) ) ; } //计算本来的总面积 55 56 For (i, 1, cnt) 57 if (win[i].flag && win[i].deep < win[num].deep) //如果在它上面 并且 未被删除 58 For (j, win[i].xl, win[i].xr-1) 59 For (k, win[i].yl, win[i].yr-1) 60 exist[j][k] = false; //小矩形置为假 61 62 For (i, win[num].xl, win[num].xr-1) 63 For (j, win[num].yl, win[num].yr-1) 64 if (exist[i][j]) //存在 就加上 65 now_area += fabs( (gx[i] - gx[i+1]) * (gy[j] - gy[j+1]) ); //计算面积 66 67 return ((double)now_area / (double)sum_area * 100.0000); //计算百分比 68 } 69 70 struct oper { 71 char opt; 72 int l, xl, yl, xr, yr; 73 }; 74 75 oper kk[N]; //存储操作 76 int cnt_op = 0; 77 vector <int> tx; //存储坐标 78 vector <int> ty; 79 80 int main(){ 81 freopen ("window.in", "r", stdin); 82 freopen ("window.out", "w", stdout); 83 char opt; 84 while (scanf ("%c", &opt) != EOF) { 85 char l; 86 int xl1, yl1, xr1, yr1; 87 if (opt == 'w') { 88 scanf ("(%c,%d,%d,%d,%d)", &l, &xl1, &yl1, &xr1, &yr1); 89 if (xl1 > xr1) swap(xl1, xr1); 90 if (yl1 > yr1) swap(yl1, yr1); //左下角 和 右上角 91 kk[++cnt_op] = (oper) {opt, l, xl1, yl1, xr1, yr1}; 92 tx.pb (xl1); tx.pb(xr1); ty.pb(yl1); ty.pb(yr1); 93 } 94 else { 95 scanf ("(%c)", &l); 96 kk[++cnt_op] = (oper) {opt, l, 0, 0, 0, 0}; 97 } 98 } 99 100 sort (tx.begin(), tx.end() ); 101 For (i, 0, tx.size() - 1) 102 if (!fx[tx[i]] ) {fx[tx[i]] = ++cnt_x; gx[cnt_x] = tx[i]; } 103 sort (ty.begin(), ty.end() ); 104 For (i, 0, ty.size() - 1) 105 if (!fy[ty[i]] ) {fy[ty[i]] = ++cnt_y; gy[cnt_y] = ty[i]; } 106 //运用map的离散化 可能有点慢 107 108 For (i, 1, cnt_op) { 109 //cout << "id: " << i << endl; 110 opt = kk[i].opt; 111 char l = kk[i].l; int num; 112 int xl1 = kk[i].xl, yl1 = kk[i].yl, xr1 = kk[i].xr, yr1 = kk[i].yr; 113 if (opt == 'w') { 114 num = idx(l); 115 win[num].xl = fx[xl1]; win[num].xr = fx[xr1]; 116 win[num].yl = fy[yl1]; win[num].yr = fy[yr1]; 117 win[num].flag = true; win[num].deep = --top_deep; //放在最上面 并将flag为真 118 } //创建一个新窗体(window) 119 else if (opt == 't') { 120 num = idx(l); 121 win[num].deep = --top_deep; 122 }//将窗体置顶(top) 123 else if (opt == 'b') { 124 num = idx(l); 125 win[num].deep = ++back_deep; 126 }//将窗体置底(back) 127 else if (opt == 'd') { 128 num = idx(l); 129 win[num].flag = false; 130 // cout << num << endl; 131 }//删除一个窗体(delete) 132 else if (opt == 's') { 133 num = idx(l); 134 printf ("%.3lf\n", sum(num)); 135 }//输出窗体可见部分的百分比(sum) 136 } 137 }