Submit: 1919 Solved: 533
[Submit][Status][Discuss]
Description
你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作:
命令 |
参数限制 |
内容 |
1 x y A |
1<=x,y<=N,A是正整数 |
将格子x,y里的数字加上A |
2 x1 y1 x2 y2 |
1<=x1<= x2<=N 1<=y1<= y2<=N |
输出x1 y1 x2 y2这个矩形内的数字和 |
3 |
无 |
终止程序 |
Input
输入文件第一行一个正整数N。
接下来每行一个操作。每条命令除第一个数字之外,
均要异或上一次输出的答案last_ans,初始时last_ans=0。
Output
对于每个2操作,输出一个对应的答案。
Sample Input
4
1 2 3 3
2 1 1 3 3
1 1 1 1
2 1 1 0 7
3
1 2 3 3
2 1 1 3 3
1 1 1 1
2 1 1 0 7
3
Sample Output
3
5
5
HINT
数据规模和约定
1<=N<=500000,操作数不超过200000个,内存限制20M,保证答案在int范围内并且解码之后数据仍合法。
样例解释见OJ2683
新加数据一组,但未重测----2015.05.24
Source
【题解】
在做kd-tree的时候会记录这个子树的最大矩形范围。如果整个最大矩形范围都在所求的矩形范围内。就直接返回这个最大矩形所在的子树的和。
如果不满足的话就看看当前节点是否在所求矩形内。
如果在就先累加这个节点的。
再递归求解左子树和右子树;
然后加的那组数据会卡时.
要不定时重建整棵树。(10000为周期)
【代码】
#include <cstdio> #include <algorithm> const int MAXN = 209000; using namespace std; struct point { int d[2], ma_x[2], mi_n[2], l, r, sum, v; }; int n, la = 0, v, root = 0, totn, a1, b1, a2, b2, now; point t[MAXN], op; void up_data(int rt) { int l = t[rt].l, r = t[rt].r; for (int i = 0; i <= 1; i++) { if (l) { t[rt].ma_x[i] = max(t[l].ma_x[i], t[rt].ma_x[i]); t[rt].mi_n[i] = min(t[l].mi_n[i], t[rt].mi_n[i]); } if (r) { t[rt].ma_x[i] = max(t[r].ma_x[i], t[rt].ma_x[i]); t[rt].mi_n[i] = min(t[r].mi_n[i], t[rt].mi_n[i]); } } t[rt].sum = t[l].sum + t[r].sum + t[rt].v;//重建后要更新sum值。 } void insert(int &rt, int fx) { if (rt == 0) //创节点。更新信息 { rt = ++totn; t[rt] = op; t[rt].l = t[rt].r = 0; for (int i = 0; i <= 1; i++) t[rt].ma_x[i] = t[rt].mi_n[i] = t[rt].d[i]; t[rt].sum = v; t[rt].v = v; return; } else { if (op.d[fx] <= t[rt].d[fx]) insert(t[rt].l, 1 - fx); else insert(t[rt].r, 1 - fx); } up_data(rt); } int query(int rt, int fx) { if (!rt) return 0; if (op.mi_n[0] <= t[rt].mi_n[0] && t[rt].ma_x[0] <= op.ma_x[0] && op.mi_n[1] <= t[rt].mi_n[1] && t[rt].ma_x[1] <= op.ma_x[1]) return t[rt].sum; //整个子树都在范围内 int temp = 0, l = t[rt].l, r = t[rt].r; if (op.mi_n[0] <= t[rt].d[0] && t[rt].d[0] <= op.ma_x[0] && op.mi_n[1] <= t[rt].d[1] && t[rt].d[1] <= op.ma_x[1]) //这个点在范围内 temp += t[rt].sum - t[l].sum - t[r].sum; //减去两个子树的就是当前这个点的 //或直接加t[rt].v if (op.mi_n[fx] <= t[rt].d[fx]) temp += query(l, 1 - fx); if (t[rt].d[fx] <= op.ma_x[fx]) temp += query(r, 1 - fx); return temp; } bool cmp(point a, point b) { if (a.d[now] < b.d[now]) return true; return false; } int build(int begin, int end, int fx) { int m = (begin + end) >> 1; now = fx; nth_element(t + begin, t + m, t + end + 1, cmp); for (int i = 0; i <= 1; i++) t[m].ma_x[i] = t[m].mi_n[i] = t[m].d[i]; t[m].sum = t[m].v; if (begin < m) t[m].l = build(begin, m - 1, 1 - fx); else t[m].l = 0; if (m < end) t[m].r = build(m + 1, end, 1 - fx); else t[m].r = 0; up_data(m); return m; } void input_data() { scanf("%d", &n); while (true) { int cz; scanf("%d", &cz); if (cz == 1) { if ((totn != 0) && (totn % 10000) == 0) //重建树 root = build(1, totn, 0); scanf("%d%d%d", &op.d[0], &op.d[1], &v); op.d[0] ^= la; op.d[1] ^= la; v ^= la; insert(root, 0); } else if (cz == 2) { scanf("%d%d%d%d", &op.mi_n[0], &op.mi_n[1], &op.ma_x[0], &op.ma_x[1]); op.mi_n[0] ^= la; op.mi_n[1] ^= la; op.ma_x[0] ^= la; op.ma_x[1] ^= la; la = query(root, 0); printf("%d ", la); } else break; } } int main() { //freopen("F:\rush.txt", "r", stdin); input_data(); return 0; }