BZOJ 1176: [Balkan2007]Mokia( CDQ分治 + 树状数组 )
考慮cdq分治, 對于[l, r)遞歸[l, m), [m, r); 然后計算[l, m)的操作對[m, r)中詢問的影響就可以了. 具體就是差分答案+排序+離散化然后樹狀數組維護.操作數為M的話時間復雜度大概是O(M(logM)^2)
-----------------------------------------------------------------------
#include<cstdio>#include<cstring>#include<algorithm>#include<cctype>using namespace std;typedef long long ll;#define cal(x, y) (ll(Val) * (x) * (y))#define lowbit(x) ((x) & -(x))#define h(v) (lower_bound(Y, Y + Yn, v) - Y + 1)#define Q(x) o[Que[x]]#define A(x) o[Ad[x]]const int MAXN = 640009;const int MAXQ = 40009;inline int read() {char c = getchar();int ret = 0, t = 0;for(; !isdigit(c); c = getchar()) if(c == '-') t = 1;for(; isdigit(c); c = getchar()) ret = ret * 10 + c - '0';return t ? -ret : ret;}int Val, On, Qn;int ans[MAXQ];int Ad[MAXN], Que[MAXQ], Adn, Quen;int Y[MAXN], Yn, X[MAXN], Xn;struct O {int p, x, y, v;inline void Set(int _p, int _x, int _y, int _v) {p = _p; x = _x; y = _y; v = _v;}bool operator < (const O &o) const {return x < o.x;}} o[MAXN + MAXQ];void Init() {Val = read();Qn = On = 0;for(int t = read(); (t = read()) != 3; ) {if(t == 1) {int x = read(), y = read();o[On++].Set(-1, x, y, read());} else {int x0 = read() - 1, y0 = read() - 1, x1 = read(), y1 = read();o[On++].Set(Qn, x0, y0, 1);o[On++].Set(Qn, x1, y1, 1);o[On++].Set(Qn, x0, y1, 0);o[On++].Set(Qn, x1, y0, 0);ans[Qn++] = cal(x0, y0) + cal(x1, y1) - cal(x1, y0) - cal(x0, y1);}}}struct BIT {int b[MAXN];BIT() {memset(b, 0, sizeof b);}void Add(int p, int v) {for(; p <= Yn; p += lowbit(p)) b[p] += v;}int Query(int p) {int ret = 0;for(; p; p -= lowbit(p)) ret += b[p];return ret;}} Bit;bool Cmp(const int &l, const int &r) {return o[l].x < o[r].x;}void Solve() {Yn = Xn = 0;for(int i = 0; i < Quen; i++)Y[Yn++] = Q(i).y, X[Xn++] = Q(i).x;for(int i = 0; i < Adn; i++)Y[Yn++] = A(i).y, X[Xn++] = A(i).x;sort(Que, Que + Quen, Cmp);sort(Ad, Ad + Adn, Cmp);sort(Y, Y + Yn); Yn = unique(Y, Y + Yn) - Y;sort(X, X + Xn); Xn = unique(X, X + Xn) - X;int _Adn = 0, _Quen = 0;for(int i = 0; i < Xn; i++) {while(_Adn < Adn && A(_Adn).x == X[i])Bit.Add(h(A(_Adn).y), A(_Adn).v), _Adn++;while(_Quen < Quen && Q(_Quen).x == X[i]) {int ret = Bit.Query(h(Q(_Quen).y));ans[Q(_Quen).p] += Q(_Quen).v ? ret : -ret;_Quen++;}}for(int i = 0; i < Adn; i++)Bit.Add(h(A(i).y), -A(i).v);}// [l, r)void CDQ(int l, int r) {if(l + 1 >= r) return;int m = (l + r) >> 1;CDQ(l, m); CDQ(m, r);Adn = Quen = 0;for(; l < m; l++)if(!~o[l].p) Ad[Adn++] = l;for(; l < r; l++)if(~o[l].p) Que[Quen++] = l;if(Quen && Adn) Solve();}int main() {Init();CDQ(0, On);for(int i = 0; i < Qn; i++)printf("%d\n", ans[i]);return 0;}-----------------------------------------------------------------------?
1176: [Balkan2007]Mokia
Time Limit:?30 Sec??Memory Limit:?162 MBSubmit:?1281??Solved:?537
[Submit][Status][Discuss]
Description
維護一個W*W的矩陣,初始值均為S.每次操作可以增加某格子的權值,或詢問某子矩陣的總權值.修改操作數M<=160000,詢問數Q<=10000,W<=2000000.
Input
第一行兩個整數,S,W;其中S為矩陣初始值;W為矩陣大小
接下來每行為一下三種輸入之一(不包含引號):
"1 x y a"
"2 x1 y1 x2 y2"
"3"
輸入1:你需要把(x,y)(第x行第y列)的格子權值增加a
輸入2:你需要求出以左上角為(x1,y1),右下角為(x2,y2)的矩陣內所有格子的權值和,并輸出
輸入3:表示輸入結束
Output
對于每個輸入2,輸出一行,即輸入2的答案
Sample Input
0 41 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3
Sample Output
35
HINT
保證答案不會超過int范圍
Source
?
轉載于:https://www.cnblogs.com/JSZX11556/p/5040186.html
總結
以上是生活随笔為你收集整理的BZOJ 1176: [Balkan2007]Mokia( CDQ分治 + 树状数组 )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 家博会门票,多钱一张?
- 下一篇: 激光手术多少钱啊?