【K-D树 求矩阵的和】BZOJ-4066 简单题

来源:互联网 发布:欧洲神话 巨人 知乎 编辑:程序博客网 时间:2024/05/05 19:51

Problem Description

输入一个N,代表有一个N*N的棋盘。
有三种操作
1 x y A : 将格子x, y里的数字加上A
2 xl yl xr yr : 输出xl yl xr yr这个矩阵内的数字和(xl <= xr, yl <= yr)
3 : 终止条件
接下来每行一个操作。每条命令除第一个数字之外,
均要异或上一次输出的答案last_ans,初始时last_ans=0。
对于每个2操作,输出一个对应的答案。

思路:

学习ldq的思路
这里插入的点的数量有点多,可能导致树的形态太差,所以插入点树每过 5000 就暴力重构一下。
注意求矩阵和函数,和线段树区间求和 还是有点相似的。
其他函数基本不变

#include<bits/stdc++.h>using namespace std;const int MAX = 200055;const int inf = 0x3f3f3f3f;const int DIM = 2;struct node{    int l, r;    int sum, v;//sum记录这个子树的和,v代表该点的值    int d[DIM], maxn[DIM], minn[DIM];    inline void maintain()//初始化    {        for(int i = 0; i < DIM; i++)            maxn[i] = minn[i] = d[i];        l = r = 0;        sum = v;    }} tree[MAX*2];int D;bool operator < (const node &a, const node &b)//重载从小到大{    return a.d[D] < b.d[D];}inline void Merge(int o)//归并,向上更新{    int son[2] = {tree[o].l, tree[o].r};    for(int i = 0; i < 2; i++)    {        if(!son[i]) continue;        for(int j = 0; j < DIM; j++)        {            tree[o].maxn[j] = max(tree[o].maxn[j], tree[son[i]].maxn[j]);            tree[o].minn[j] = min(tree[o].minn[j], tree[son[i]].minn[j]);        }    }    tree[o].sum = tree[o].v + tree[son[0]].sum + tree[son[1]].sum;}int build(int l, int r, int now)//建树{    int mid = (l+r) >> 1;    D = now;    nth_element(tree+l, tree+mid, tree+r+1);    tree[mid].maintain();    if(l < mid) tree[mid].l = build(l, mid-1, (now+1)%DIM);    if(r > mid) tree[mid].r = build(mid+1, r, (now+1)%DIM);    Merge(mid);    return mid;}void Insert(int &o, int k, int now)//插入{    if(o == 0)    {        o = k;        return ;    }    if(tree[k].d[now] < tree[o].d[now]) Insert(tree[o].l, k, (now+1)%DIM);    else Insert(tree[o].r, k, (now+1)%DIM);    Merge(o);}int xl, xr, yl, yr;int ans;void query(int o)//求和{    if(xr < tree[o].minn[0] || xl > tree[o].maxn[0] || yl > tree[o].maxn[1] || yr < tree[o].minn[1])//这个子树,不在所求范围内        return;    if(xl <= tree[o].minn[0] && xr >= tree[o].maxn[0] && yl <= tree[o].minn[1] && yr >= tree[o].maxn[1])//所求范围,包含子树    {        ans += tree[o].sum;        return;    }    if(xl <= tree[o].d[0] && xr >= tree[o].d[0] && yl <= tree[o].d[1] && yr >= tree[o].d[1])//部分包含        ans += tree[o].v;    if(tree[o].l) query(tree[o].l);    if(tree[o].r) query(tree[o].r);}int read(){    int t;    scanf("%d", &t);    return ans^t;}int main(){    int n;    scanf("%d", &n);    int pos = 1, op;    int root = 0;    ans = 0;    while(true)    {        scanf("%d", &op);        if(op == 1)        {            for(int i = 0; i < DIM; i++)                tree[pos].d[i] = read();            tree[pos].v = read();            tree[pos].maintain();            Insert(root, pos, 0);            pos++;            if(pos % 5000 == 0)                root = build(1, pos-1, 0);        }        else if(op == 2)        {            xl = read();            yl = read();            xr = read();            yr = read();            ans = 0;            query(root);            printf("%d\n", ans);        }        else break;    }    return 0;}