【BZOJ2683】简单题 [分治][树状数组]
简单题
Time Limit: 50 Sec Memory Limit: 128 MB[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。
Solution
首先把询问拆成4个,那么我们就只要维护一个点左下角权值和了。
然后对所有操作按照 x 升序排序。
对 y 用个树状数组求前缀和,(由于 x 升序,所以此时询问已经相当于对y求前缀和了)
以mid为分界线,考虑左区间对右区间的影响。
显然,我们可以把左区间的修改执行,然后执行右区间的询问。
这样我们就做完了这道题。
Code
1 #include<iostream> 2 #include<string> 3 #include<algorithm> 4 #include<cstdio> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cmath> 8 using namespace std; 9 typedef long long s64; 10 11 const int ONE = 1000005; 12 const int INF = 214748340; 13 14 int get() 15 { 16 int res = 1, Q = 1; char c; 17 while( (c = getchar()) < 48 || c > 57) 18 if(c == '-') Q = -1; 19 if(Q) res = c - 48; 20 while( (c = getchar()) >= 48 && c <= 57) 21 res = res * 10 + c - 48; 22 return res * Q; 23 } 24 25 int n; 26 namespace BIT 27 { 28 int C[ONE]; 29 int lowbit(int i) {return i & -i;} 30 void Add(int R, int x) 31 { 32 for(int i = R; i <= n; i += lowbit(i)) 33 C[i] += x; 34 } 35 int Query(int R) 36 { 37 int res = 0; 38 for(int i = R; i >= 1; i -= lowbit(i)) 39 res += C[i]; 40 return res; 41 } 42 } 43 44 int id, query_num, Ans[ONE]; 45 struct power 46 { 47 int id, opt, from; 48 int x, y, val; 49 }oper[ONE], q[ONE]; 50 51 bool cmp(const power &a, const power &b) 52 { 53 if(a.x != b.x) return a.x < b.x; 54 return a.opt < b.opt; 55 } 56 57 void Deal(int x_1, int y_1, int x_2, int y_2) 58 { 59 query_num++; 60 oper[++id] = (power){id, 2, query_num, x_2, y_2, 1}; 61 oper[++id] = (power){id, 2, query_num, x_1 - 1, y_1 - 1, 1}; 62 oper[++id] = (power){id, 2, query_num, x_1 - 1, y_2, -1}; 63 oper[++id] = (power){id, 2, query_num, x_2, y_1 - 1, -1}; 64 } 65 66 void Solve(int l, int r) 67 { 68 if(l >= r) return; 69 70 int mid = l + r >> 1; 71 for(int i = l; i <= r; i++) 72 { 73 if(oper[i].opt == 1 && oper[i].id <= mid) 74 BIT::Add(oper[i].y, oper[i].val); 75 if(oper[i].opt == 2 && oper[i].id > mid) 76 Ans[oper[i].from] += BIT::Query(oper[i].y) * oper[i].val; 77 } 78 79 for(int i = l; i <= r; i++) 80 if(oper[i].opt == 1 && oper[i].id <= mid) 81 BIT::Add(oper[i].y, -oper[i].val); 82 83 int tl = l, tr = mid + 1; 84 for(int i = l; i <= r; i++) 85 if(oper[i].id <= mid) q[tl++] = oper[i]; 86 else q[tr++] = oper[i]; 87 88 for(int i = l; i <= r; i++) 89 oper[i] = q[i]; 90 91 Solve(l, mid), Solve(mid + 1, r); 92 } 93 94 int opt, x_1, y_1, x_2, y_2; 95 96 int main() 97 { 98 n = get(); 99 for(;;) 100 { 101 opt = get(); 102 if(opt == 3) break; 103 if(opt == 1) 104 oper[++id].id = id, oper[id].opt = 1, 105 oper[id].x = get(), oper[id].y = get(), oper[id].val = get(); 106 if(opt == 2) 107 x_1 = get(), y_1 = get(), 108 x_2 = get(), y_2 = get(), 109 Deal(x_1, y_1, x_2, y_2); 110 } 111 112 sort(oper + 1, oper + id + 1, cmp); 113 114 Solve(1, id); 115 116 for(int i = 1; i <= query_num; i++) 117 printf("%d\n", Ans[i]); 118 }