UVAlive7141 BombX 14年上海区域赛D题 线段树+离散化
题意:一个无限大的棋盘, 有n个小兵, 给出了n个兵的坐标, 现在有一个长为width 高为height的炸弹放在棋盘上, 炸弹只能上下左右平移, 不能旋转。
且放炸弹的区域不能含有士兵, 炸弹可以一次炸掉与它同一行同一列的所有士兵。 放一颗炸弹, 使得炸死的士兵最多。输出最大值。
思路:先不考虑离散化, 可以计算出水平方向和竖直方向上所有长度为width和height区间内士兵的个数, 得到一个数组prefixX, prefixY。
然后一次遍历prefixY数组, 假设区间[i, i+height-1]对应prefixY[i], 而且[i, i+height-1]内所有士兵的x坐标对应的prefixX都减去一个大于n的数字MAX(这样保证炸弹不会放在士兵上),这个时候求prefixX上的一个最大值max再加上prefixY[i]就可以更新答案result了, 如果max是一个负数那么说明当前这个区间不能放炸弹。 之后再把第i行的所有士兵的x坐标对应的prefixX都加上MAX。 这样一次下去就可以了。线段树区间操作。
还有一个需要特判的地方是 上面并没有找到一个可以放炸弹的地方。 这个时候答案就是prefixX和prefixY的最大值。
思路一下子就想出来了,可是怎么离散化想了好久。。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 2e5 + 5; 4 struct SegTree{ 5 int seg[maxn << 2], lazy[maxn << 2]; 6 void build(int l, int r, int pos, int val[]){ 7 lazy[pos] = 0; 8 if (l == r){ 9 seg[pos] = val[l]; 10 return; 11 } 12 int mid = (l + r) >> 1; 13 build(l, mid, pos<<1, val); 14 build(mid+1, r, pos<<1|1, val); 15 seg[pos] = max(seg[pos<<1], seg[pos<<1|1]); 16 } 17 void push_down(int pos){ 18 if (lazy[pos]){ 19 seg[pos<<1] += lazy[pos]; 20 seg[pos<<1|1] += lazy[pos]; 21 lazy[pos<<1] += lazy[pos]; 22 lazy[pos<<1|1] += lazy[pos]; 23 lazy[pos] = 0; 24 } 25 } 26 void update (int l, int r, int pos, int ua, int ub, int val){ 27 if (ua > ub){ 28 return; 29 } 30 if (ua <= l && ub >= r){ 31 seg[pos] += val; 32 lazy[pos] += val; 33 return; 34 } 35 push_down(pos); 36 int mid = (l + r) >> 1; 37 if (ua <= mid){ 38 update(l, mid, pos<<1, ua, ub, val); 39 } 40 if (ub > mid){ 41 update(mid+1, r, pos<<1|1, ua, ub, val); 42 } 43 seg[pos] = max(seg[pos<<1], seg[pos<<1|1]); 44 } 45 }tree; 46 int pawX[maxn], pawY[maxn]; 47 int lshX[maxn], lshY[maxn], tot1, tot2; 48 int prefixX[maxn], prefixY[maxn], valX[maxn], valY[maxn]; 49 vector <int> vec1[maxn], vec2[maxn]; 50 void init(){ 51 memset(prefixX, 0, sizeof prefixX); 52 memset(prefixY, 0, sizeof prefixY); 53 for (int i = 0; i < maxn; i++){ 54 vec1[i].clear(); 55 vec2[i].clear(); 56 } 57 } 58 int main(){ 59 int T, cas = 1; 60 scanf ("%d", &T); 61 while (T--){ 62 int n, width, height; 63 scanf ("%d%d%d", &n, &width, &height); 64 tot1 = tot2 = 0; 65 init(); 66 for (int i = 0; i < n; i++){ 67 int x, y; 68 scanf ("%d%d", &x, &y); 69 pawX[i] = x, pawY[i] = y; 70 lshX[tot1++] = x; 71 lshX[tot1++] = x - width+1; 72 lshY[tot2++] = y; 73 lshY[tot2++] = y-height+1; 74 } 75 sort(lshX, lshX+tot1); 76 sort(lshY, lshY+tot2); 77 tot1 = unique(lshX, lshX+tot1) - lshX; 78 tot2 = unique(lshY, lshY+tot2) - lshY; 79 for (int i = 0; i < n; i++){ 80 int x1 = lower_bound(lshX, lshX+tot1, pawX[i]-width+1) - lshX + 1; 81 int x2 = lower_bound(lshX, lshX+tot1, pawX[i]) - lshX + 1; 82 int y1 = lower_bound(lshY, lshY+tot2, pawY[i]-height+1) - lshY + 1; 83 int y2 = lower_bound(lshY, lshY+tot2, pawY[i]) - lshY + 1; 84 prefixX[x1]++; prefixX[x2+1]--; 85 prefixY[y1]++; prefixY[y2+1]--; 86 vec1[y1].push_back(i); 87 vec2[y2].push_back(i); 88 } 89 int res = 0; 90 for (int i = 1; i <= tot1; i++){ 91 prefixX[i] += prefixX[i-1]; 92 res = max(res, prefixX[i]); // 这里要特判一下 93 } 94 for (int i = 1; i <= tot2; i++){ 95 prefixY[i] += prefixY[i-1]; 96 res = max(res, prefixY[i]); // 这里要特判一下 97 } 98 tree.build(1, tot1, 1, prefixX); 99 const int tenThousand = 1e5; 100 for (int i = 1; i <= tot2; i++){ 101 for (int j = 0; j < vec1[i].size(); j++){ 102 int idx = vec1[i][j]; 103 int x = lower_bound(lshX, lshX+tot1, pawX[vec1[i][j]]) - lshX + 1; 104 int y = lower_bound(lshX, lshX+tot1, pawX[vec1[i][j]]-width+1) - lshX + 1; 105 tree.update(1, tot1, 1, y, x, -tenThousand); 106 } 107 int ret = tree.seg[1]; 108 if (ret > 0) 109 res = max(res, prefixY[i]+ret); 110 for (int j = 0; j < vec2[i].size(); j++){ 111 int x = lower_bound(lshX, lshX+tot1, pawX[vec2[i][j]]) - lshX + 1; 112 int y = lower_bound(lshX, lshX+tot1, pawX[vec2[i][j]]-width+1) - lshX + 1; 113 tree.update(1, tot1, 1, y, x, tenThousand); 114 } 115 } 116 printf("Case #%d: %d\n", cas++, res); 117 } 118 return 0; 119 }