题意:
给定一个 n × n 的棋盘,每个格子初始权值为 0,现有 m 次操作,①:1,x,y,v,在格子 ( x,y ) 加上权值 v;② :2,x1,y1,x2,y2,询问此子矩阵内的权值和。(n <= 5e5, m <= 2e5,内存限制20Mb,时限50s,强制在线)
链接:
https://vjudge.net/problem/HYSBZ-4066
解题思路:
这是一个经典问题,离线做法有如cdq分治、树状数组,在线做法有如树套树,半在线的主席树等(有空要整理一下),但是在这里通通用不了。这里用 K-D Tree 来解决,空间O(n),插入O(logn),查询O(
n
\sqrt{n}
n)(k = 2维)。
然后,维护的东西比较多写成结构体会快一些,特别是这题 50s,第一次遇到这么长时限的,结果用非结构体写 T 到飞起,都是血泪啊。
参考代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define pb push_back
#define sz(a) ((int)a.size())
#define mem(a, b) memset(a, b, sizeof a)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 2e5 + 5;
const int maxm = 5e2 + 5;
const int mod = 998244353;
const int inf = 0x3f3f3f3f;
const int maxs = 1e3 + 5;
char buf[maxs], *p1 = buf, *p2 = buf;
inline char fr(){
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, maxs, stdin)) == p1 ? -1 : *p1++;
}
#define gc fr()
inline void read(int &x){
char ch; while(!isdigit(ch = gc)); x = ch ^ 48;
while(isdigit(ch = gc)) x = x * 10 + (ch ^ 48);
}
int idx, n, k, rt, tot, cnt;
struct Point{
int x[2], w;
bool operator < (const Point &o) const{
return x[idx] < o.x[idx];
}
} pi[maxn];
struct Node{
Point po;
int ls, rs, mn[2], mx[2], siz, sum;
} tr[maxn];
int rub[maxn], top;
const double ak = 0.625;
inline int add(){
if(top) return rub[top--];
return ++tot;
}
void pushUp(int rt){
int l = tr[rt].ls, r = tr[rt].rs;
for(int i = 0; i < k; ++i){
tr[rt].mn[i] = tr[rt].mx[i] = tr[rt].po.x[i];
if(l) tr[rt].mn[i] = min(tr[rt].mn[i], tr[l].mn[i]);
if(r) tr[rt].mn[i] = min(tr[rt].mn[i], tr[r].mn[i]);
if(l) tr[rt].mx[i] = max(tr[rt].mx[i], tr[l].mx[i]);
if(r) tr[rt].mx[i] = max(tr[rt].mx[i], tr[r].mx[i]);
}
tr[rt].siz = tr[l].siz + tr[r].siz + 1;
tr[rt].sum = tr[l].sum + tr[r].sum + tr[rt].po.w;
}
void build(int l, int r, int &rt, int d){
rt = add(); tr[rt].ls = tr[rt].rs = 0;
int mid = gmid; idx = d;
nth_element(pi + l, pi + mid, pi + 1 + r);
tr[rt].po = pi[mid];
if(l < mid) build(l, mid - 1, tr[rt].ls, d ^ 1);
if(r > mid) build(mid + 1, r, tr[rt].rs, d ^ 1);
pushUp(rt);
}
inline int check(int rt){
if(max(tr[tr[rt].ls].siz, tr[tr[rt].rs].siz) > tr[rt].siz * ak) return 1;
return 0;
}
void print(int rt){
if(tr[rt].ls) print(tr[rt].ls);
if(tr[rt].rs) print(tr[rt].rs);
pi[++cnt] = tr[rt].po, rub[++top] = rt;
}
void rebuild(int &rt, int d){
cnt = 0;
print(rt);
build(1, cnt, rt, d);
}
void update(int &rt, int d, Point &a){
if(!rt){
rt = add(); tr[rt].ls = tr[rt].rs = 0;
tr[rt].po = a; pushUp(rt);
return;
}
if(a.x[d] <= tr[rt].po.x[d]) update(tr[rt].ls, d ^ 1, a);
else update(tr[rt].rs, d ^ 1, a);
pushUp(rt);
if(check(rt)) rebuild(rt, d);
}
int query(int rt, int x1, int y1, int x2, int y2){
if(!rt || x2 < tr[rt].mn[0] || x1 > tr[rt].mx[0] || y2 < tr[rt].mn[1] || y1 > tr[rt].mx[1]) return 0;
if(x1 <= tr[rt].mn[0] && x2 >= tr[rt].mx[0] && y1 <= tr[rt].mn[1] && y2 >= tr[rt].mx[1]) return tr[rt].sum;
int ret = 0;
if(x1 <= tr[rt].po.x[0] && x2 >= tr[rt].po.x[0] && y1 <= tr[rt].po.x[1] && y2 >= tr[rt].po.x[1]) ret += tr[rt].po.w;
return ret + query(tr[rt].ls, x1, y1, x2, y2) + query(tr[rt].rs, x1, y1, x2, y2);
}
int main(){
read(n); k = 2;
int opt, x1, y1, x2, y2, ret = 0;
while(1){
read(opt);
if(opt == 1){
Point a;
read(a.x[0]), read(a.x[1]), read(a.w);
a.x[0] ^= ret, a.x[1] ^= ret, a.w ^= ret;
update(rt, 0, a);
}
else if(opt == 2){
read(x1), read(y1), read(x2), read(y2);
x1 ^= ret, y1 ^= ret, x2 ^= ret, y2 ^= ret;
ret = query(rt, x1, y1, x2, y2);
printf("%d\n", ret);
}
else break;
}
return 0;
}