[BOI2007]Mokia 摩基亚

												[BOI2007]Mokia 摩基亚

link:https://www.luogu.org/problemnew/show/P4390

题意大概就是每次在二维平面上的一个点加上一个值,然后询问一个矩阵内的权值和
经典的二维数点问题
由于可以离线,所以CDQ分治即可
把矩阵询问拆成4个前缀和的形式
时间一维, x一维, y一维
经典的三维偏序问题
注意坐标从0开始,lowbit(0)=0,所以要加一个偏移量
然鹅由于一些小问题调了一下午
code:

// luogu-judger-enable-o2
#include
#define int long long
#define lowbit(x) (x & -x)
#define N 5000005
using namespace std;
struct A{
    int a, b, val, o, id;
}a[N], del[N];
int cmp(A x, A y){
    return x.a < y.a;
}
int tree[N], ANS[N], F[N], tot, n;
void update(int x, int y){
    for(;x <= n; x += lowbit(x)) tree[x] += y;
}
int query(int x){
    int ret = 0;
    for(; x; x -= lowbit(x)) ret += tree[x];
    return ret;
}
void cdq(int l, int r){//三维偏序板子
    if(l == r) return;
    int mid = (l + r) >> 1;
    cdq(l, mid), cdq(mid + 1, r);
    sort(a + l, a + mid + 1, cmp), sort(a + mid + 1, a + r + 1, cmp);
    int szz = 0, p = l - 1;
    for(int i = mid + 1; i <= r; i ++){
        while(a[p + 1].a <= a[i].a && p < mid){
            ++ p;
            if(a[p].o == 0) update(a[p].b, a[p].val), del[++ szz] = a[p];
        }
        if(a[i].o == 1)	F[a[i].id] = 1, ANS[a[i].id] += query(a[i].b);
    }
    for(int i = 1; i <= szz; i ++) update(del[i].b, -del[i].val);
}
signed main(){
    scanf("%lld%lld", &n, &n);
    n ++;//注意!!!!!就这里我调了一下午,n要加1的偏移量
    while(1){
        int opt, x, y, xx, yy, z;
        scanf("%lld", &opt);
        if(opt == 3) break;
        if(opt == 1){
            scanf("%lld%lld%lld", &x, &y, &z);
            x ++, y ++;//加一个偏移量
            a[++ tot] = A{x, y, z, 0, tot};
        }
        if(opt == 2){
            scanf("%lld%lld%lld%lld", &x, &y, &xx, &yy);
            x ++, y ++, xx ++, yy ++;//加一个偏移量
            a[++ tot] = A{xx, yy, 0, 1, tot};//把矩阵拆成4个前缀和
            a[++ tot] = A{xx, y - 1, 0, 1, tot};
            a[++ tot] = A{x - 1, yy, 0, 1, tot};
            a[++ tot] = A{x - 1, y - 1, 0, 1, tot};		
        }
 	}
 	cdq(1, tot);
 //	for(int i = 1; i <= tot; i ++) printf("%lld ", ANS[i]); printf("\n");
 	for(int i = 1; i <= tot; i ++){
 		if(F[i]) printf("%lld\n", ANS[i] - ANS[i + 1] - ANS[i + 2] + ANS[i + 3]), i += 3;
     }
    return 0;
}

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