【27.77%】【BZOJ 4066】简单题

来源:互联网 发布:大学生有多少存款知乎 编辑:程序博客网 时间:2024/05/21 21:45

Time Limit: 50 Sec  Memory Limit: 20 MB
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

Sample Output

3
5

HINT

数据规模和约定

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

样例解释见OJ2683


新加数据一组,但未重测----2015.05.24


Source

By wjy1998


【题解】

在做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);elseinsert(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].vif (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);elset[m].l = 0;if (m < end)t[m].r = build(m + 1, end, 1 - fx);elset[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);}elseif (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\n", la);}elsebreak;}}int main(){//freopen("F:\\rush.txt", "r", stdin);input_data();return 0;}


0 0
原创粉丝点击