bzoj1176 [Balkan2007]Mokia

[Balkan2007]Mokia

Time Limit: 30 Sec Memory Limit: 162 MB

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 4

1 2 3 3

2 1 1 3 3

1 2 2 2

2 2 2 3 4

3

Sample Output

3

5

HINT

保证答案不会超过int范围



CDQ分治了解一下。。。
这个东西有点厉害啊。。。离线操作总有一些好方法啊。。。
大概就是降维打击。。。
每次都只管前面一半对后面一半的贡献,然后分治。
其实还是降维打击最为致命啊
这道题是个入门题。。。。自己瞎yy了一波。。。我只是打错了 i 和 p2 就调了很久。。。但还是是 1A 的啦(傲娇~)
详细解法早就烂大街了。。。但是我看的是论文


#include<bits/stdc++.h>
#define lowbit(x) (x & (-x))
using namespace std;
const int maxn = 2e6 + 6;
struct lpl{
    int mark, opt, x, y, id;
}ini[200005], tmp[200005];
int w, s, opt, q, cnt, ans[10005], tree[maxn];

inline void SRT(int l, int r)
{
    int mid = (l + r) >> 1;
    int p1 = l, p2 = mid + 1, p = l - 1;
    while(p1 <= mid && p2 <= r){
        if(p1 <= mid && p2 <= r && ini[p1].x <= ini[p2].x) tmp[++p] = ini[p1++];
        if(p1 <= mid && p2 <= r && ini[p1].x > ini[p2].x) tmp[++p] = ini[p2++];
    }
    for(int i = p1; i <= mid; ++i) tmp[++p] = ini[i];
    for(int i = p2; i <= r; ++i) tmp[++p] = ini[i];
    for(int i = l; i <= r; ++i) ini[i] = tmp[i];
}

inline void Modify(int t, int val)
{
    if(!t) return;
    while(t < maxn){
        tree[t] += val; t += lowbit(t);
    }
}

inline int Query(int t)
{
    int ret = 0;
    if(!t) return ret;
    while(t){
        ret += tree[t];
        t -= lowbit(t);
    }
    return ret;
}

void CDQ(int l, int r)
{
    if(l == r) return;
    int mid = (l + r) >> 1;
    CDQ(l, mid); CDQ(mid + 1, r);
    SRT(l, mid); SRT(mid + 1, r);
    int p1 = l, p2 = mid + 1, tot = 0;
    while(p1 <= mid && p2 <= r){
        while(p1 <= mid && p2 <= r && ini[p1].x <= ini[p2].x){
            if(ini[p1].opt == 2){p1++; continue;}
            Modify(ini[p1].y, ini[p1].mark); tot++; tmp[tot] = ini[p1]; p1++;
        }
        if(p1 > mid || p2 > r) break;
        if(ini[p2].opt == 2){
            ans[ini[p2].id] += Query(ini[p2].y) * ini[p2].mark; p2++; continue;
        }
        p2++;
    }
    for(int i = p2; i <= r; ++i) 
        if(ini[i].opt == 2) 
            ans[ini[i].id] += Query(ini[i].y) * ini[i].mark;
    for(int i = 1; i <= tot; ++i) 
    Modify(tmp[i].y, -tmp[i].mark);
}

int main()
{
    int x1, x2, y1, y2;
    scanf("%d%d", &w, &s);
    while(1){
        scanf("%d", &opt);
        if(opt == 3) break;
        if(opt == 2){
            q++; scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
            ini[++cnt].opt = 2; ini[cnt].mark = 1; ini[cnt].x = x2; ini[cnt].y = y2; ini[cnt].id = q;
            ini[++cnt].opt = 2; ini[cnt].mark = -1; ini[cnt].x = x1 - 1; ini[cnt].y = y2; ini[cnt].id = q;
            ini[++cnt].opt = 2; ini[cnt].mark = -1; ini[cnt].x = x2; ini[cnt].y = y1 - 1; ini[cnt].id = q;
            ini[++cnt].opt = 2; ini[cnt].mark = 1; ini[cnt].x = x1 - 1; ini[cnt].y = y1 - 1; ini[cnt].id = q;
        }
        if(opt == 1){
            ini[++cnt].opt = 1;
            scanf("%d%d%d", &ini[cnt].x, &ini[cnt].y, &ini[cnt].mark);
        }
    }
    CDQ(1, cnt);
    for(int i = 1; i <= q; ++i) printf("%d\n", ans[i]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/LLppdd/p/9184988.html