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;
}