2683: 简单题
Time Limit: 50 Sec Memory Limit: 128 MBSubmit: 913 Solved: 379
[Submit][Status][Discuss]
Description
你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作:
命令 |
参数限制 |
内容 |
1 x y A |
1<=x,y<=N,A是正整数 |
将格子x,y里的数字加上A |
2 x1 y1 x2 y2 |
1<=x1<= x2<=N 1<=y1<= y2<=N |
输出x1 y1 x2 y2这个矩形内的数字和 |
3 |
无 |
终止程序 |
Input
输入文件第一行一个正整数N。
接下来每行一个操作。
Output
对于每个2操作,输出一个对应的答案。
Sample Input
4
1 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3
1 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3
Sample Output
3
5
5
HINT
1<=N<=500000,操作数不超过200000个,内存限制20M。
对于100%的数据,操作1中的A不超过2000。
Source
分析
离线CDQ分治,对于预处理后的所有操作(查询)按照X坐标排序,然后用树状数组维护Y坐标上的前缀和。
代码
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 const int N = 500005; 6 const int M = 200005; 7 8 template <class T> 9 __inline void read(T &x) 10 { 11 x = 0; 12 bool f = false; 13 char c = getchar(); 14 15 while (c < '0') 16 { 17 if (c == '-') 18 f ^= true; 19 c = getchar(); 20 } 21 22 while (c >= '0') 23 { 24 x = x*10 + c - '0'; 25 c = getchar(); 26 } 27 28 if (f)x = -x; 29 } 30 31 struct operation 32 { 33 int id, op, to, x, y, d; 34 }q[M << 2], tmp[M << 2]; 35 36 int cmp(const void *a, const void *b) 37 { 38 operation *A = (operation *)a; 39 operation *B = (operation *)b; 40 41 if (A->x != B->x) 42 return A->x - B->x; 43 if (A->y != B->y) 44 return A->y - B->y; 45 return A->op - B->op; 46 } 47 48 int n, m, t; 49 50 void pushQuery(void) 51 { 52 int x1; read(x1); 53 int y1; read(y1); 54 int x2; read(x2); 55 int y2; read(y2); 56 57 ++t; 58 { 59 ++m; 60 q[m].d = 1; 61 q[m].op = 2; 62 q[m].id = m; 63 q[m].to = t; 64 q[m].x = x1 - 1; 65 q[m].y = y1 - 1; 66 } 67 { 68 ++m; 69 q[m].d = 1; 70 q[m].op = 2; 71 q[m].id = m; 72 q[m].to = t; 73 q[m].x = x2; 74 q[m].y = y2; 75 } 76 { 77 ++m; 78 q[m].d = -1; 79 q[m].op = 2; 80 q[m].id = m; 81 q[m].to = t; 82 q[m].y = y2; 83 q[m].x = x1 - 1; 84 } 85 { 86 ++m; 87 q[m].d = -1; 88 q[m].op = 2; 89 q[m].id = m; 90 q[m].to = t; 91 q[m].x = x2; 92 q[m].y = y1 - 1; 93 } 94 } 95 96 int answer[M]; 97 98 void printAnswer(void) 99 { 100 for (int i = 1; i <= t; ++i) 101 printf("%d ", answer[i]); 102 } 103 104 namespace binaryInsertTree 105 { 106 int tree[N]; 107 108 void change(int p, int v) 109 { 110 for (int i = p; i <= n; i += i & -i) 111 tree[i] += v; 112 } 113 114 int query(int p) 115 { 116 int ret = 0; 117 118 for (int i = p; i >= 1; i -= i & -i) 119 ret += tree[i]; 120 121 return ret; 122 } 123 } 124 125 void divideAndConquer(int l, int r) 126 { 127 if (l != r) 128 { 129 int mid = (l + r) >> 1; 130 131 for (int i = l; i <= r; ++i) 132 { 133 if (q[i].op == 1 && q[i].id <= mid) 134 binaryInsertTree::change(q[i].y, q[i].d); 135 if (q[i].op == 2 && q[i].id > mid) 136 answer[q[i].to] += binaryInsertTree::query(q[i].y) * q[i].d; 137 } 138 139 for (int i = l; i <= r; ++i) 140 if (q[i].op == 1 && q[i].id <= mid) 141 binaryInsertTree::change(q[i].y, -q[i].d); 142 143 int t1 = l, t2 = mid + 1; 144 145 for (int i = l; i <= r; ++i) 146 { 147 if (q[i].id <= mid) 148 tmp[t1++] = q[i]; 149 else 150 tmp[t2++] = q[i]; 151 } 152 153 for (int i = l; i <= r; ++i) 154 q[i] = tmp[i]; 155 156 divideAndConquer(l, mid); 157 divideAndConquer(mid + 1, r); 158 } 159 } 160 161 signed main(void) 162 { 163 read(n); 164 165 for (m = t = 0; ; ) 166 { 167 int opt; read(opt); 168 169 if (opt == 3)break; 170 171 switch (opt) 172 { 173 case 1 : 174 ++m; 175 q[m].op = 1; 176 q[m].id = m; 177 read(q[m].x); 178 read(q[m].y); 179 read(q[m].d); 180 break; 181 case 2 : 182 pushQuery(); 183 } 184 } 185 186 qsort(q + 1, m, sizeof(operation), cmp); 187 188 divideAndConquer(1, m); 189 190 printAnswer(); 191 }
@Author: YouSiki