BZOJ 1176 Mokia(cdq分治,解决一类在线查询问题)

题意:维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数Q<=10000,W<=2000000.

这题在bz是贵族题= =,没有链接了

解法:cdq分治,第一维是时间t,第二维是x,第三维是y;每个操作看作一个三维序(t, x, y);假设修改操作是(t, x, y),两个查询操作分别是(t1, x1, y1) 和 (t1, x2, y2);实际上就要问,有多少个修改操作,满足t<=t1,x1<=x<=x2,y1<=y<=y2;这个用cdq分治就能做了,要将查询拆成四个点,利用容斥原理来做。不愿意细讲了= =,具体看代码吧

My code

//Hello. I'm Peter.
//#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<cctype>
#include<ctime>
#include<stack>
#include<queue>
#include<vector>
#include<bitset>
#include<set>
#include<map>
using namespace std;
#define peter cout<<"i am peter"<<endl
#define fuck(x) cerr << #x << " <- " << x << endl
typedef long long ll;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

#define N 200010
int w,n,li[N],nli,ans[N];
struct Pair{
    int ty, id;
    int x, y, v;
    Pair(){};
    Pair(int ty1,int id1,int x1,int y1,int v1){
        ty = ty1, id = id1,x = x1, y = y1, v = v1;
    }
}p[N],s1[N],s2[N];
bool cmp1(const Pair a, const Pair b){
    return a.x < b.x;
}

int sum[N];
void add(int x,int v){
    for(int i = x; i <= nli; i += i&-i){
        sum[i] += v;
    }
}
int query(int x){
    int ans = 0;
    for(int i = x; i > 0; i -= i&-i){
        ans += sum[i];
    }
    return ans;
}
void clear(int x){
    for(int i = x; i <= nli; i += i&-i){
        sum[i] = 0;
    }
}


void cdq(int l,int r){
    if(l == r) return;
    int mid = (l + r) >> 1;
    cdq(l, mid);

    int n1 = 0, n2 = 0;
    for(int i = l; i <= mid; i++) if(p[i].ty == 1) s1[++n1] = p[i];
    for(int i = mid + 1; i <= r; i++) if(p[i].ty == 2) s2[++n2] = p[i];
    sort(s1 + 1, s1 + 1 + n1, cmp1);
    sort(s2 + 1, s2 + 1 + n2, cmp1);

    int t1 = 1;
    for(int t2 = 1; t2 <= n2; t2++){
        for(;t1 <= n1 && s1[t1].x <= s2[t2].x; t1++){
            add(s1[t1].y, s1[t1].v);
        }
        int id = s2[t2].id;
        ans[id] += s2[t2].v * query(s2[t2].y);
    }
    for(int i = 1; i < t1; i++){
        clear(s1[i].y);
    }

    cdq(mid + 1, r);
}

bool isq[N];
int nop;
int main(){
    int t; t = read();
    w = read();
    for(int i = 1; ;i++){
        t = read();
        if(t == 3) break;

        nop = nop + 1;
        if(t == 1){
            isq[i] = 0;
            int x,y,v;
            x = read(), y = read(), v = read();
            p[++n] = Pair(t, i, x, y, v);
            li[++nli] = y;
        }
        else if(t == 2){
            isq[i] = 1;
            int x1,y1,x2,y2;
            x1 = read(), y1 = read(), x2 = read(), y2 = read();
            p[++n] = Pair(t, i, x2, y2, +1);
            p[++n] = Pair(t, i, x2, y1 - 1, -1);
            p[++n] = Pair(t, i, x1 - 1, y2, -1);
            p[++n] = Pair(t, i, x1 - 1, y1 - 1, +1);
            li[++nli] = y2;
            li[++nli] = y1 - 1;
        }
    }

    sort(li + 1, li + 1 + nli);
    nli = (int)(unique(li + 1, li + 1 + nli) - (li + 1));
    for(int i = 1; i <= n; i++){
        p[i].y = (int)(lower_bound(li + 1, li + 1 + nli, p[i].y) - li);
    }

    for(int i = 1; i <= nli; i++) sum[i] = 0;
    for(int i = 1; i <= nop; i++) ans[i] = 0;
    cdq(1, n);

    for(int i = 1; i <= nop; i++){
        if(isq[i]) printf("%d\n",ans[i]);
    }
    return 0;
}

你可能感兴趣的:(cdq分治)