试题描述
你有一个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 |
无 |
终止程序 |
输入
输入文件第一行一个正整数N。
接下来每行一个操作。每条命令除第一个数字之外,
均要异或上一次输出的答案last_ans,初始时last_ans=0。(BZOJ2683不需要强制在线)
输出
对于每个2操作,输出一个对应的答案。
输入示例(BZOJ2683)
4 1 2 3 3 2 1 1 3 3 1 2 2 2 2 2 2 3 4 3
输出示例(BZOJ2683)
3 5
输入示例(BZOJ4066)
4 1 2 3 3 2 1 1 3 3 1 1 1 1 2 1 1 0 7 3
输出示例(BZOJ4066)
3 5
数据规模及约定
数据规模和约定
1<=N<=500000,操作数不超过200000个,内存限制20M,保证答案在int范围内并且解码之后数据仍合法。
题解
只有权限号可以享受的双倍经验题(雾)。
2683这道数据水,最裸的kd树就卡时限过了。。。
4066这题数据强,需要加一个定期重构,就是加入的元素达到了某一些固定值就暴力把整棵kd树重新构造一遍,这样就不会被卡成“n2 的优秀算法了”。
2683(不强制在线无定期重构慢的要死):
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <stack> #include <vector> #include <queue> #include <cstring> #include <string> #include <map> #include <set> using namespace std; const int BufferSize = 1 << 16; char buffer[BufferSize], *Head, *Tail; inline char Getchar() { if(Head == Tail) { int l = fread(buffer, 1, BufferSize, stdin); Tail = (Head = buffer) + l; } return *Head++; } int read() { int x = 0, f = 1; char c = Getchar(); while(!isdigit(c)){ if(c == ‘-‘) f = -1; c = Getchar(); } while(isdigit(c)){ x = x * 10 + c - ‘0‘; c = Getchar(); } return x * f; } #define maxn 200010 #define oo 2147483647 int root, ToT, lc[maxn], rc[maxn]; struct Node { int x[2], mx[2], mn[2], val, sum; bool operator == (const Node& t) const { return x[0] == t.x[0] && x[1] == t.x[1]; } } nodes[maxn]; Node x, y; void maintain(int o) { int l = lc[o], r = rc[o]; for(int i = 0; i < 2; i++) { nodes[o].mx[i] = max(max(nodes[l].mx[i], nodes[r].mx[i]), nodes[o].x[i]); nodes[o].mn[i] = min(min(nodes[l].mn[i], nodes[r].mn[i]), nodes[o].x[i]); } nodes[o].sum = nodes[l].sum + nodes[r].sum + nodes[o].val; // printf("maintain(%d): %d %d %d %d %d\n", o, nodes[o].sum, nodes[o].mx[0], nodes[o].mn[0], nodes[o].mx[1], nodes[o].mn[1]); return ; } void add(int& o, bool cur) { if(!o){ nodes[o = ++ToT] = x; return maintain(o); } if(nodes[o] == x){ nodes[o].val += x.val; nodes[o].sum += x.val; return maintain(o); } add(x.x[cur] < nodes[o].x[cur] ? lc[o] : rc[o], cur ^ 1); return maintain(o); } bool all(int o) { return x.x[0] <= nodes[o].mn[0] && nodes[o].mx[0] <= y.x[0] && x.x[1] <= nodes[o].mn[1] && nodes[o].mx[1] <= y.x[1]; } bool has(int o) { return !(nodes[o].mx[0] < x.x[0] || nodes[o].mn[0] > y.x[0] || nodes[o].mx[1] < x.x[1] || nodes[o].mn[1] > y.x[1]); } int query(int o) { if(!o) return 0; int ans = 0; if(all(lc[o])) ans += nodes[lc[o]].sum; else if(has(lc[o])) ans += query(lc[o]); if(all(rc[o])) ans += nodes[rc[o]].sum; else if(has(rc[o])) ans += query(rc[o]); int nx = nodes[o].x[0], ny = nodes[o].x[1]; if(x.x[0] <= nx && nx <= y.x[0] && x.x[1] <= ny && ny <= y.x[1]) ans += nodes[o].val; return ans; } int main() { nodes[0].mx[0] = nodes[0].mx[1] = -oo; nodes[0].mn[0] = nodes[0].mn[1] = oo; nodes[0].val = nodes[0].sum = 0; int n = read(); n = read(); while(n < 3) { if(n == 1) { x.x[0] = read(); x.x[1] = read(); x.val = read(); add(root, 1); } if(n == 2) { x.x[0] = read(); x.x[1] = read(); y.x[0] = read(); y.x[1] = read(); printf("%d\n", query(root)); } n = read(); } return 0; }
4066(强制在线加定期重构但还是很慢= =):
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <stack> #include <vector> #include <queue> #include <cstring> #include <string> #include <map> #include <set> using namespace std; const int BufferSize = 1 << 16; char buffer[BufferSize], *Head, *Tail; inline char Getchar() { if(Head == Tail) { int l = fread(buffer, 1, BufferSize, stdin); Tail = (Head = buffer) + l; } return *Head++; } int read() { int x = 0, f = 1; char c = Getchar(); while(!isdigit(c)){ if(c == ‘-‘) f = -1; c = Getchar(); } while(isdigit(c)){ x = x * 10 + c - ‘0‘; c = Getchar(); } return x * f; } #define maxn 200010 #define oo 2147483647 int root, ToT, lc[maxn], rc[maxn]; bool Cur; struct Node { int x[2], mx[2], mn[2], val, sum; bool operator == (const Node& t) const { return x[0] == t.x[0] && x[1] == t.x[1]; } bool operator < (const Node& t) const { return x[Cur] < t.x[Cur]; } } nodes[maxn]; Node x, y; void maintain(int o) { int l = lc[o], r = rc[o]; for(int i = 0; i < 2; i++) { nodes[o].mx[i] = max(max(nodes[l].mx[i], nodes[r].mx[i]), nodes[o].x[i]); nodes[o].mn[i] = min(min(nodes[l].mn[i], nodes[r].mn[i]), nodes[o].x[i]); } nodes[o].sum = nodes[l].sum + nodes[r].sum + nodes[o].val; // printf("maintain(%d): %d %d %d %d %d\n", o, nodes[o].sum, nodes[o].mx[0], nodes[o].mn[0], nodes[o].mx[1], nodes[o].mn[1]); return ; } void add(int& o, bool cur) { if(!o){ nodes[o = ++ToT] = x; return maintain(o); } if(nodes[o] == x){ nodes[o].val += x.val; nodes[o].sum += x.val; return maintain(o); } add(x.x[cur] < nodes[o].x[cur] ? lc[o] : rc[o], cur ^ 1); return maintain(o); } void build(int& o, int L, int R, int cur) { if(L > R){ o = 0; return ; } int M = L + R >> 1; o = M; Cur = cur; nth_element(nodes + L, nodes + M, nodes + R + 1); build(lc[o], L, M - 1, cur ^ 1); build(rc[o], M + 1, R, cur ^ 1); return maintain(o); } bool all(int o) { return x.x[0] <= nodes[o].mn[0] && nodes[o].mx[0] <= y.x[0] && x.x[1] <= nodes[o].mn[1] && nodes[o].mx[1] <= y.x[1]; } bool has(int o) { return !(nodes[o].mx[0] < x.x[0] || nodes[o].mn[0] > y.x[0] || nodes[o].mx[1] < x.x[1] || nodes[o].mn[1] > y.x[1]); } int query(int o) { if(!o) return 0; int ans = 0; if(all(lc[o])) ans += nodes[lc[o]].sum; else if(has(lc[o])) ans += query(lc[o]); if(all(rc[o])) ans += nodes[rc[o]].sum; else if(has(rc[o])) ans += query(rc[o]); int nx = nodes[o].x[0], ny = nodes[o].x[1]; if(x.x[0] <= nx && nx <= y.x[0] && x.x[1] <= ny && ny <= y.x[1]) ans += nodes[o].val; return ans; } int main() { nodes[0].mx[0] = nodes[0].mx[1] = -oo; nodes[0].mn[0] = nodes[0].mn[1] = oo; nodes[0].val = nodes[0].sum = 0; int n = read(), lastans = 0; n = read(); while(n < 3) { if(n == 1) { x.x[0] = read() ^ lastans; x.x[1] = read() ^ lastans; x.val = read() ^ lastans; add(root, 1); if(ToT % 1000 == 0) build(root, 1, ToT, 1); } if(n == 2) { x.x[0] = read() ^ lastans; x.x[1] = read() ^ lastans; y.x[0] = read() ^ lastans; y.x[1] = read() ^ lastans; printf("%d\n", lastans = query(root)); } n = read(); } return 0; }
其实这道题我第一眼看上去是树套树删边题,结果一看内存限制20M。。。还好没写树套树= =
时间: 2024-10-28 10:34:11