【BZOJ2683】簡單題 [分治][樹狀數組]
阿新 • • 發佈:2017-11-07
math 所有 操作數 def 正整數 || lap ref 維護
[Submit][Status][Discuss]
1 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3
5
了。
簡單題
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
41 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3
Sample Output
35
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 }View Code
【BZOJ2683】簡單題 [分治][樹狀數組]