P4148 简单题

题目链接
题目描述
你有一个 N × N N \times N N×N 的棋盘,每个格子内有一个整数,初始时的时候全部为 0 0 0 ,现在需要维护两种操作:

  • 1 x y A 1 ≤ x , y ≤ N 1\le x,y\le N 1x,yN A A A 是正整数。将格子 x,y 里的数字加上 A A A
  • 2 x1 y1 x2 y2 1 ≤ x 1 ≤ x 2 ≤ N 1 \le x_1 \le x_2 \le N 1x1x2N 1 ≤ y 1 ≤ y 2 ≤ N 1 \le y_1\le y_2 \le N 1y1y2N。输出 x 1 , y 1 , x 2 , y 2 x_1, y_1, x_2, y_2 x1,y1,x2,y2 这个矩形内的数字和
  • 3 无 终止程序

输入格式
输入文件第一行一个正整数 N N N

接下来每行一个操作。每条命令除第一个数字之外,均要异或上一次输出的答案last_ans,初始时last_ans = 0 =0 =0

输出格式
对于每个 2 2 2 操作,输出一个对应的答案。

输入输出样例
输入 #1

4
1 2 3 3
2 1 1 3 3
1 1 1 1
2 1 1 0 7
3

输出 #1

3
5

说明/提示
1 < = N < = 500000 1<=N<=500000 1<=N<=500000 ,操作数不超过 200000 200000 200000 个,内存限制20M,保证答案在int范围内并且解码之后数据仍合法。

#include<bits/stdc++.h>

using namespace std;

inline int qr() {
    int f = 0, fu = 1;
    char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-')fu = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        f = (f << 3) + (f << 1) + c - 48;
        c = getchar();
    }
    return f * fu;
}

const int N = 2e5 + 10;
const double alpha = 0.75;

struct K_D_Tree {
    int d[N], lc[N], rc[N];
    int xl, xr, yl, yr, cur, rt;
    int siz[N], sum[N];
    struct node {
        int x, y, v;
    } p[N];
    int L[N], R[N], D[N], U[N];
    int g[N];

    inline void update(int x) {
        sum[x] = sum[lc[x]] + sum[rc[x]] + p[x].v;
        siz[x] = siz[lc[x]] + siz[rc[x]] + 1;
        L[x] = R[x] = p[x].x, D[x] = U[x] = p[x].y;
        if (lc[x]) {
            L[x] = min(L[x], L[lc[x]]), R[x] = max(R[x], R[lc[x]]);
            D[x] = min(D[x], D[lc[x]]), U[x] = max(U[x], U[lc[x]]);
        }
        if (rc[x]) {
            L[x] = min(L[x], L[rc[x]]), R[x] = max(R[x], R[rc[x]]);
            D[x] = min(D[x], D[rc[x]]), U[x] = max(U[x], U[rc[x]]);
        }
    }

    int build(int l, int r) {
        if (l > r)return 0;
        int mid = (l + r) >> 1;
        double avx = 0, avy = 0, vax = 0, vay = 0;
        for (int i = l; i <= r; i++)avx += p[g[i]].x, avy += p[g[i]].y;
        avx /= 1.0 * (r - l + 1), avy /= 1.0 * (r - l + 1);
        for (int i = l; i <= r; i++) {
            vax += (p[g[i]].x - avx) * (p[g[i]].x - avx);
            vay += (p[g[i]].y - avy) * (p[g[i]].y - avy);
        }
        if (vax > vay)
            nth_element(g + l, g + mid, g + r + 1, [&](int i, int j) {
                return p[i].x < p[j].x;
            }), d[g[mid]] = 1;
        else
            nth_element(g + l, g + mid, g + r + 1, [&](int i, int j) {
                return p[i].y < p[j].y;
            }), d[g[mid]] = 2;
        lc[g[mid]] = build(l, mid - 1), rc[g[mid]] = build(mid + 1, r), update(g[mid]);
        return g[mid];
    }

    int q[N];

    void insert(int &x, int v) {
        if (!x) return update(x = v), void();
        insert(((d[x] == 1 ? p[v].x <= p[x].x : p[v].y <= p[x].y) ? lc : rc)[x], v);
        update(x);
        if (alpha * siz[x] <= (double) max(siz[lc[x]], siz[rc[x]])) {
            int t = 0, l = 1, r = 1;
            q[1] = x;
            while (l <= r) {
                int u = g[++t] = q[l++];
                if (lc[u])q[++r] = lc[u];
                if (rc[u])q[++r] = rc[u];
            }
            x = build(1, t);
        }
    }

    int ans;

    int query(int x) {
        if (!x || xr < L[x] || xl > R[x] || yr < D[x] || yl > U[x])return 0;
        if (xl <= L[x] && R[x] <= xr && yl <= D[x] && U[x] <= yr)return sum[x];
        int res = 0;
        if (xl <= p[x].x && p[x].x <= xr && yl <= p[x].y && p[x].y <= yr)res = p[x].v;
        return query(lc[x]) + query(rc[x]) + res;
    }

    inline void change(int x, int y, int v) {
        p[++cur] = {x ^ ans, y ^ ans, v ^ ans};
        insert(rt, cur);
    }

    inline int ask(int _xl, int _xr, int _yl, int _yr) {
        xl = _xl ^ ans, yl = _yl ^ ans, xr = _xr ^ ans, yr = _yr ^ ans;
        return ans = query(rt);
    }
} K;

int main() {
    qr();
    while (true)
        switch (qr()) {
            case 1: {
                int x = qr(), y = qr(), v = qr();
                K.change(x, y, v);
                break;
            }
            case 2: {
                int xl = qr(), yl = qr(), xr = qr(), yr = qr();
                printf("%d\n", K.ask(xl, xr, yl, yr));
                break;
            }
            default:
                return 0;
        }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_sky123_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值