发现自己的树套树太菜了
cdq嵌套也太菜了
面对多维的问题直接上天
于是就去学了下K-Dtree,发现不是很难的亚子
K-Dtree的本质就是一颗二叉搜索树,一般的二叉搜索树是按数的大小来划分左右儿子的
K-Dtree就是每次随机(或者轮换)按照一维来划分成二叉搜索树的左右儿子,实现很简单。
假设现在要把a[i]建成一颗K-Dtree
首先随便按照a[i]的一维排序。
然后取中间那个作为根,分成左右部分作为两颗子树,递归下去建树
但是要排序很不优美,c++中有一个好用的stl叫做nth_element,具体的用法是
nth_element(a + l, a + mid, a + r + 1, cmp)
表示的就是a[mid]就是a数组的中位数,比中位数小的在a[l…mid-1],大的在a[mid+1…r]非常方便
建树就是场这样
int build(int l, int r, int o) { //o表示按照那一维划分
if(l > r) return 0;
int mid = (l + r) >> 1;
if(!o) nth_element(a + l, a + mid, a + r + 1, cmp1) ;
else nth_element(a + l, a + mid, a + r + 1, cmp2);//划分
ch[mid][0] = build(l, mid - 1, o ^ 1);//递归下去建树
ch[mid][1] = build(mid + 1, r, o ^ 1);
update(mid);
return mid;
}
可能会有人问?这样怎么就可以保证时间复杂度
其实好像也不能保证,但是基本卡不掉
当然最好就是每一维算出方差,取方差最大的一维来划分,写起来麻烦一些而已
这种划分好像是 O ( n 2 − 1 D ) \large O(n^{2-\frac{1}{D}}) O(n2−D1), D是维数
然后来集体练习一下
luogu P4357 [CQOI2016]K远点对
这题用K-Dtree的时间复杂度是假的
但是可以当作入门题来练练。
K-Dtree有个重要的地方就是方便剪枝
这题就维护子树范围内最大最小的横纵坐标,算可能最大的情况作为估值
比较左右子树的估值,哪边估值大就先往哪边跑。
如果估值<=已知最大的就没有必要跑了
code;
#include
#define N 1000005
#define int long long
using namespace std;
struct A {
int x, y;
} a[N];
int cmp1(A x, A y) {
return x.x < y.x;
}
int cmp2(A x, A y) {
return x.y < y.y;
}
int L[N], R[N], D[N], U[N], ch[N][2], n, k;
void update(int x) {
L[x] = R[x] = a[x].x;
D[x] = U[x] = a[x].y;
if(ch[x][0]) {
L[x] = min(L[x], L[ch[x][0]]), R[x] = max(R[x], R[ch[x][0]]);
D[x] = min(D[x], D[ch[x][0]]), U[x] = max(U[x], U[ch[x][0]]);
}
if(ch[x][1]) {
L[x] = min(L[x], L[ch[x][1]]), R[x] = max(R[x], R[ch[x][1]]);
D[x] = min(D[x], D[ch[x][1]]), U[x] = max(U[x], U[ch[x][1]]);
}
}
int build(int l, int r, int o) {
if(l > r) return 0;
int mid = (l + r) >> 1;
if(!o) nth_element(a + l, a + mid, a + r + 1, cmp1);
else nth_element(a + l, a + mid, a + r + 1, cmp2);
ch[mid][0] = build(l, mid - 1, o ^ 1);
ch[mid][1] = build(mid + 1, r, o ^ 1);
update(mid);
return mid;
}
int pf(int x) { return x * x;}
int getmax(int x, int y) {
return max(pf(a[x].x - L[y]), pf(a[x].x - R[y])) + max(pf(a[x].y - D[y]), pf(a[x].y - U[y]));
}
priority_queue<int, vector<int>, greater<int> > q;
void query(int l, int r, int id) {
if(l > r) return;
int mid = (l + r) >> 1, t = pf(a[mid].x - a[id].x) + pf(a[mid].y - a[id].y);
if(t > q.top()) q.pop(), q.push(t);
int disl = getmax(id, ch[mid][0]), disr = getmax(id, ch[mid][1]);
if(disl > disr) {
if(disl > q.top()) query(l, mid - 1, id);
if(disr > q.top()) query(mid + 1, r, id);
} else {
if(disr > q.top()) query(mid + 1, r, id);
if(disl > q.top()) query(l, mid - 1, id);
}
}
signed main() {
scanf("%lld%lld", &n, &k); k <<= 1;
for(int i = 1; i <= k; i ++) q.push(0);
for(int i = 1; i <= n; i ++) scanf("%lld%lld", &a[i].x, &a[i].y);
build(1, n, 0);
for(int i = 1; i <= n; i ++) query(1, n, i);
printf("%lld", q.top());
return 0;
}
看代码能懂。
P3769 [CH弱省胡策R2]TATT
可以说是四维偏序板子题
cdq套cdq套cdq好像写起来很麻烦
其他的解法好像也很麻烦
而且要三个log
可以考虑K-Dtree
但是这题还要插入
直接插入的话就会不平衡,考虑如何让它平衡
K-Dtree是不支持旋转的,所以可以用类似替罪羊树的思想拍扁重建
然后就没了
平衡因子好像比较玄学
code:
#include
#define N 1000005
using namespace std;
int mi[N][5], ma[N][5], mf[N], f[N], sz, ch[N][2], size[N], ls[N], tot, dd, root, d[N];
struct T {
int a[5];
} t[N];
void update(int x) {
mi[x][0] = ma[x][0] = t[x].a[0];
mi[x][1] = ma[x][1] = t[x].a[1];
mi[x][2] = ma[x][2] = t[x].a[2];
mf[x] = f[x];
if(ch[x][0]) {
mf[x] = max(mf[x], mf[ch[x][0]]);
for(int i = 0; i < 3; i ++)
mi[x][i] = min(mi[x][i], mi[ch[x][0]][i]),
ma[x][i] = max(ma[x][i], ma[ch[x][0]][i]);
}
if(ch[x][1]) {
mf[x] = max(mf[x], mf[ch[x][1]]);
for(int i = 0; i < 3; i ++)
mi[x][i] = min(mi[x][i], mi[ch[x][1]][i]),
ma[x][i] = max(ma[x][i], ma[ch[x][1]][i]);
}
size[x] = size[ch[x][0]] + size[ch[x][1]] + 1;
}
void dfs(int x) {
if(!x) return;
dfs(ch[x][0]);
ls[++ sz] = x;
dfs(ch[x][1]);
}
int cmpp(int x, int y) {
return t[x].a[dd] < t[y].a[dd];
}
int build(int l, int r, int o) {
if(l > r) return 0;
int mid = (l + r) >> 1;
dd = o;
nth_element(ls + l, ls + mid, ls + r + 1, cmpp);
int rt = ls[mid];
d[rt] = o;
ch[rt][0] = build(l, mid - 1, (o + 1) % 3);
ch[rt][1] = build(mid + 1, r, (o + 1) % 3);
update(rt);
return rt;
}
void rebuild(int &x) {
sz = 0;
dfs(x);
x = build(1, sz, 0);
}
const double alpha = 0.725;
bool bad(int x) {return alpha * size[x] <= (double)max(size[ch[x][0]], size[ch[x][1]]);}
void insert(int &x, int y) {
if(!x) {
x = y;
update(x);
return;
}
if(t[y].a[d[x]] <= t[x].a[d[x]]) insert(ch[x][0], y);
else insert(ch[x][1], y);
update(x);
if(bad(x)) rebuild(x);
}
int ans = 0;
void query(int x, int y) {
if(!x || t[y].a[0] < mi[x][0] || t[y].a[1] < mi[x][1] || t[y].a[2] < mi[x][2]) return ;
if(t[x].a[0] <= t[y].a[0] && t[x].a[1] <= t[y].a[1] && t[x].a[2] <= t[y].a[2])ans = max(ans, f[x]);
if(mf[x] <= ans) return;
if(ma[x][0] <= t[y].a[0] && ma[x][1] <= t[y].a[1] && ma[x][2] <= t[y].a[2]) {
ans = max(ans, mf[x]);
return;
}
query(ch[x][0], y), query(ch[x][1], y);
}
int n;
struct A {
int a[5];
} a[N];
int cmp(A x, A y) {
if(x.a[0] != y.a[0]) return x.a[0] < y.a[0];
if(x.a[1] != y.a[1]) return x.a[1] < y.a[1];
if(x.a[2] != y.a[2]) return x.a[2] < y.a[2];
return x.a[3] < y.a[3];
}
int main() {
srand(time(NULL));
scanf("%d", &n);
for(int i = 1; i <= n; i ++) scanf("%d%d%d%d", &a[i].a[0], &a[i].a[1], &a[i].a[2], &a[i].a[3]);
sort(a + 1, a + 1 + n, cmp);
for(int i = 1; i <= n; i ++) {
t[++ tot] = T{a[i].a[1], a[i].a[2], a[i].a[3]};
ans = 0;
query(root, tot);
f[tot] = ans + 1;
insert(root, tot);
}
ans = 0;
for(int i = 1; i <= n; i ++) ans = max(ans, f[i]);
printf("%d", ans);
return 0;
}
P4475 巧克力王国
这题关键也是在估值函数上
如果子树最大的x和y都不行就不用进入子树了
然后就没了
code:
#include
#define N 1000005
#define int long long
using namespace std;
int mi[N][5], ma[N][5], mf[N], f[N], sz, ch[N][2], size[N], ls[N], tot, dd, root, d[N], m, n;
struct T {
int a[5];
} t[N];
void update(int x) {
mi[x][0] = ma[x][0] = t[x].a[0];
mi[x][1] = ma[x][1] = t[x].a[1];
mf[x] = f[x];
if(ch[x][0]) {
mf[x] += mf[ch[x][0]];
for(int i = 0; i < 2; i ++)
mi[x][i] = min(mi[x][i], mi[ch[x][0]][i]),
ma[x][i] = max(ma[x][i], ma[ch[x][0]][i]);
}
if(ch[x][1]) {
mf[x] += mf[ch[x][1]];
for(int i = 0; i < 2; i ++)
mi[x][i] = min(mi[x][i], mi[ch[x][1]][i]),
ma[x][i] = max(ma[x][i], ma[ch[x][1]][i]);
}
size[x] = size[ch[x][0]] + size[ch[x][1]] + 1;
}
void dfs(int x) {
if(!x) return;
dfs(ch[x][0]);
ls[++ sz] = x;
dfs(ch[x][1]);
}
int cmpp(int x, int y) {
return t[x].a[dd] < t[y].a[dd];
}
int build(int l, int r, int o) {
if(l > r) return 0;
int mid = (l + r) >> 1;
dd = o;
nth_element(ls + l, ls + mid, ls + r + 1, cmpp);
int rt = ls[mid];
d[rt] = o;
ch[rt][0] = build(l, mid - 1, (o + 1) % 2);
ch[rt][1] = build(mid + 1, r, (o + 1) % 2);
update(rt);
return rt;
}
int ans = 0;
void query(int x, int a, int b, int c) {
int tt = 0;
tt += ma[x][0] * a + ma[x][1] * b < c;
tt += ma[x][0] * a + mi[x][1] * b < c;
tt += mi[x][0] * a + ma[x][1] * b < c;
tt += mi[x][0] * a + mi[x][1] * b < c;
if(tt == 4) {
ans += mf[x];
return;
}
if(tt == 0) return;
if(a * t[x].a[0] + b * t[x].a[1] < c) ans += f[x];
query(ch[x][0], a, b, c), query(ch[x][1], a, b, c);
}
signed main() {
srand(time(NULL));
scanf("%lld%lld", &n, &m);
for(int i = 1; i <= n; i ++) {
++ tot;
scanf("%lld%lld%lld", &t[tot].a[0], &t[tot].a[1], &f[tot]);
ls[++ sz] = tot;
}
root = build(1, sz, 0);
for(int i = 1; i <= m; i ++) {
ans = 0;
int a, b, c;
scanf("%lld%lld%lld", &a, &b, &c);
query(root, a, b, c);
printf("%lld\n", ans);
}
return 0;
}
P2093 [国家集训队]JZPFAR
这题和第一题有什么区别???
code:
#include
#define N 1000005
#define int long long
using namespace std;
struct A {
int x, y, id;
} a[N];
int cmp1(A x, A y) {
return x.x < y.x;
}
int cmp2(A x, A y) {
return x.y < y.y;
}
int L[N], R[N], D[N], U[N], ch[N][2], n, k, X, Y, m;
void update(int x) {
L[x] = R[x] = a[x].x;
D[x] = U[x] = a[x].y;
if(ch[x][0]) {
L[x] = min(L[x], L[ch[x][0]]), R[x] = max(R[x], R[ch[x][0]]);
D[x] = min(D[x], D[ch[x][0]]), U[x] = max(U[x], U[ch[x][0]]);
}
if(ch[x][1]) {
L[x] = min(L[x], L[ch[x][1]]), R[x] = max(R[x], R[ch[x][1]]);
D[x] = min(D[x], D[ch[x][1]]), U[x] = max(U[x], U[ch[x][1]]);
}
}
int build(int l, int r, int o) {
if(l > r) return 0;//printf(" %d %d\n", l, r);
int mid = (l + r) >> 1;
if(!o) nth_element(a + l, a + mid, a + r + 1, cmp1);
else nth_element(a + l, a + mid, a + r + 1, cmp2);
ch[mid][0] = build(l, mid - 1, o ^ 1);
ch[mid][1] = build(mid + 1, r, o ^ 1);
update(mid);
return mid;
}
int pf(int x) { return x * x;}
int getmax(int y) {
return max(pf(X - L[y]), pf(X - R[y])) + max(pf(Y - D[y]), pf(Y - U[y]));
}
struct AA {
int dis, id;
};
bool operator < (AA x, AA y) {
if(x.dis != y.dis) return x.dis > y.dis;
return x.id < y.id;
}
priority_queue<AA> q;
void query(int x) {
if(!x) return;
int t = pf(a[x].x - X) + pf(a[x].y - Y); //printf(" %d (%d)\n", x, t);
if(t > q.top().dis || (q.top().dis == t && a[x].id < q.top().id)) q.pop(), q.push(AA{t, a[x].id});//, printf("*%d*", t);;
int disl = getmax(ch[x][0]), disr = getmax(ch[x][1]);
if(disl > disr) {
if(disl >= q.top().dis) query(ch[x][0]);
if(disr >= q.top().dis) query(ch[x][1]);
} else {
if(disr >= q.top().dis) query(ch[x][1]);
if(disl >= q.top().dis) query(ch[x][0]);
}
// query(ch[x][0]), query(ch[x][1]);
}
signed main() {
scanf("%lld", &n);
for(int i = 1; i <= n; i ++) scanf("%lld%lld", &a[i].x, &a[i].y), a[i].id = i;
int root = build(1, n, 0);
scanf("%lld", &m);
for(int i = 1; i <= m; i ++) {
scanf("%lld%lld%lld", &X, &Y, &k);
while(q.size()) q.pop();
for(int j = 1; j <= k; j ++) q.push(AA{-1, 0});
query(root);
printf("%lld\n", q.top().id);
}
return 0;
}
P4849 寻找宝藏
和四维偏序那题差不多
多维护一个东西
code:
#include
#define N 1000005
#define ll long long
#define mod 998244353
using namespace std;
ll mi[N][5], ma[N][5], mf[N], f[N];
int sz, ch[N][2], size[N], ls[N], tot, dd, root, d[N], ms[N], gs[N];
struct T {
int a[5];
} t[N];
inline void MOD(int &x) {
if(x >= mod) x -= mod;
}
void update(int x) {
mi[x][0] = ma[x][0] = t[x].a[0];
mi[x][1] = ma[x][1] = t[x].a[1];
mi[x][2] = ma[x][2] = t[x].a[2];
mf[x] = f[x];
ms[x] = gs[x];
if(ch[x][0]) {
if(mf[ch[x][0]] == mf[x]) {
ms[x] += ms[ch[x][0]];
MOD(ms[x]);
} else
if(mf[ch[x][0]] > mf[x]) {
mf[x] = mf[ch[x][0]];
ms[x] = ms[ch[x][0]];
}
for(int i = 0; i < 3; i ++)
mi[x][i] = min(mi[x][i], mi[ch[x][0]][i]),
ma[x][i] = max(ma[x][i], ma[ch[x][0]][i]);
}
if(ch[x][1]) {
if(mf[ch[x][1]] == mf[x]) {
ms[x] += ms[ch[x][1]];
MOD(ms[x]);
} else
if(mf[ch[x][1]] > mf[x]) {
mf[x] = mf[ch[x][1]];
ms[x] = ms[ch[x][1]];
}
for(int i = 0; i < 3; i ++)
mi[x][i] = min(mi[x][i], mi[ch[x][1]][i]),
ma[x][i] = max(ma[x][i], ma[ch[x][1]][i]);
}
size[x] = size[ch[x][0]] + size[ch[x][1]] + 1;
}
void dfs(int x) {
if(!x) return;
dfs(ch[x][0]);
ls[++ sz] = x;
dfs(ch[x][1]);
}
int cmpp(int x, int y) {
return t[x].a[dd] < t[y].a[dd];
}
int build(int l, int r, int o) {
if(l > r) return 0;
int mid = (l + r) >> 1;
dd = o;
nth_element(ls + l, ls + mid, ls + r + 1, cmpp);
int rt = ls[mid];
d[rt] = o;
ch[rt][0] = build(l, mid - 1, (o + 1) % 3);
ch[rt][1] = build(mid + 1, r, (o + 1) % 3);
update(rt);
return rt;
}
void rebuild(int &x) {
sz = 0;
dfs(x);
x = build(1, sz, 0);
}
const double alpha = 0.725;
bool bad(int x) {return alpha * size[x] <= (double)max(size[ch[x][0]], size[ch[x][1]]);}
void insert(int &x, int y) {
if(!x) {
x = y;
update(x);
return;
}
if(t[y].a[d[x]] <= t[x].a[d[x]]) insert(ch[x][0], y);
else insert(ch[x][1], y);
update(x);
if(bad(x)) rebuild(x);
}
ll ans = 0;
int anss = 0;
void query(int x, int y) {
if(!x || t[y].a[0] < mi[x][0] || t[y].a[1] < mi[x][1] || t[y].a[2] < mi[x][2]) return ;
if(ma[x][0] <= t[y].a[0] && ma[x][1] <= t[y].a[1] && ma[x][2] <= t[y].a[2]) {
if(mf[x] == ans) anss += ms[x], MOD(anss);
else
if(mf[x] > ans) ans = mf[x], anss = ms[x];
return;
}
if(t[x].a[0] <= t[y].a[0] && t[x].a[1] <= t[y].a[1] && t[x].a[2] <= t[y].a[2]) {
if(f[x] == ans) anss += gs[x], MOD(anss);
else
if(f[x] > ans) ans = f[x], anss = gs[x];
}
if(mf[x] < ans) return;
query(ch[x][0], y), query(ch[x][1], y);
}
int n, m;
struct A {
int a[5]; int val;
} a[N];
int cmp(A x, A y) {
if(x.a[0] != y.a[0]) return x.a[0] < y.a[0];
if(x.a[1] != y.a[1]) return x.a[1] < y.a[1];
if(x.a[2] != y.a[2]) return x.a[2] < y.a[2];
return x.a[3] < y.a[3];
}
int main() {
srand(time(NULL));
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++) scanf("%d%d%d%d%d", &a[i].a[0], &a[i].a[1], &a[i].a[2], &a[i].a[3], &a[i].val);
sort(a + 1, a + 1 + n, cmp);
for(int i = 1; i <= n; i ++) {
t[++ tot] = T{a[i].a[1], a[i].a[2], a[i].a[3]};
ans = 0, anss = 1;
query(root, tot);
f[tot] = ans + a[i].val;
gs[tot] = anss;
insert(root, tot);
}
ans = 0, anss = 0;
for(int i = 1; i <= n; i ++) {
if(ans == f[i]) anss += gs[i], MOD(anss);
else if(f[i] > ans) ans = f[i], anss = gs[i];
}
printf("%lld\n%d", ans, anss);
return 0;
}
luogu P2479 [SDOI2010]捉迷藏
维护最大最小就好了
code:
#include
#define N 1000005
#define ll long long
using namespace std;
struct A {
int x, y, id;
} a[N];
int cmp1(A x, A y) {
return x.x < y.x;
}
int cmp2(A x, A y) {
return x.y < y.y;
}
int L[N], R[N], D[N], U[N], ch[N][2], n, k, X, Y, m;
void update(int x) {
L[x] = R[x] = a[x].x;
D[x] = U[x] = a[x].y;
if(ch[x][0]) {
L[x] = min(L[x], L[ch[x][0]]), R[x] = max(R[x], R[ch[x][0]]);
D[x] = min(D[x], D[ch[x][0]]), U[x] = max(U[x], U[ch[x][0]]);
}
if(ch[x][1]) {
L[x] = min(L[x], L[ch[x][1]]), R[x] = max(R[x], R[ch[x][1]]);
D[x] = min(D[x], D[ch[x][1]]), U[x] = max(U[x], U[ch[x][1]]);
}
}
int build(int l, int r, int o) {
if(l > r) return 0;
int mid = (l + r) >> 1;
if(!o) nth_element(a + l, a + mid, a + r + 1, cmp1);
else nth_element(a + l, a + mid, a + r + 1, cmp2);
ch[mid][0] = build(l, mid - 1, o ^ 1);
ch[mid][1] = build(mid + 1, r, o ^ 1);
update(mid);
return mid;
}
int ans, anss;
int getmin(int y) {
return max(X - R[y], 0) + max(L[y] - X, 0) + max(Y - U[y], 0) + max(D[y] - Y, 0);
}
int getmax(int y) {
return max(abs(X - L[y]), abs(X - R[y])) + max(abs(Y - D[y]), abs(Y - U[y]));
}
void querymax(int x) {
if(!x) return;
int t = abs(a[x].x - X) + abs(a[x].y - Y);
ans = max(ans, t);
int disl = getmax(ch[x][0]), disr = getmax(ch[x][1]);
if(disl > disr) {
if(disl > ans) querymax(ch[x][0]);
if(disr > ans) querymax(ch[x][1]);
} else {
if(disr > ans) querymax(ch[x][1]);
if(disl > ans) querymax(ch[x][0]);
}
}
void querymin(int x) {
if(!x) return;
int t = abs(a[x].x - X) + abs(a[x].y - Y);
if(t) anss = min(t, anss);
int disl = getmin(ch[x][0]), disr = getmin(ch[x][1]);
if(disl < disr) {
if(disl < anss) querymin(ch[x][0]);
if(disr < anss) querymin(ch[x][1]);
} else {
if(disr < anss) querymin(ch[x][1]);
if(disl < anss) querymin(ch[x][0]);
}
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i ++) scanf("%d%d", &a[i].x, &a[i].y), a[i].id = i;
int root = build(1, n, 0), ANS = 2147483647;
for(int i = 1; i <= n; i ++) {
X = a[i].x, Y = a[i].y;
ans = 0, anss = 2147483647;
querymax(root), querymin(root);
ANS = min(ANS, ans - anss);
}
printf("%d", ANS);
return 0;
}
P4148 简单题
单点修改,矩阵求和
其实这个才是板子题
不过前面也讲了,不平衡直接拍扁重建就好了
code:
#include
#define N 1000005
using namespace std;
int mi[N][5], ma[N][5], sum[N], sz, f[N], ch[N][2], size[N], ls[N], tot, dd, root, d[N];
struct T {
int a[5];
} t[N];
void update(int x) {
mi[x][0] = ma[x][0] = t[x].a[0];
mi[x][1] = ma[x][1] = t[x].a[1];
sum[x] = f[x];
if(ch[x][0]) {
sum[x] += sum[ch[x][0]];
for(int i = 0; i < 3; i ++)
mi[x][i] = min(mi[x][i], mi[ch[x][0]][i]),
ma[x][i] = max(ma[x][i], ma[ch[x][0]][i]);
}
if(ch[x][1]) {
sum[x] += sum[ch[x][1]];
for(int i = 0; i < 3; i ++)
mi[x][i] = min(mi[x][i], mi[ch[x][1]][i]),
ma[x][i] = max(ma[x][i], ma[ch[x][1]][i]);
}
size[x] = size[ch[x][0]] + size[ch[x][1]] + 1;
}
void dfs(int x) {
if(!x) return;
dfs(ch[x][0]);
ls[++ sz] = x;
dfs(ch[x][1]);
}
int cmpp(int x, int y) {
return t[x].a[dd] < t[y].a[dd];
}
int build(int l, int r, int o) {
if(l > r) return 0;
int mid = (l + r) >> 1;
dd = o;
nth_element(ls + l, ls + mid, ls + r + 1, cmpp);
int rt = ls[mid];
d[rt] = o;
ch[rt][0] = build(l, mid - 1, o ^ 1);
ch[rt][1] = build(mid + 1, r, o ^ 1);
update(rt);
return rt;
}
void rebuild(int &x) {
sz = 0;
dfs(x);
x = build(1, sz, 0);
}
const double alpha = 0.765;
bool bad(int x) {return alpha * size[x] <= (double)max(size[ch[x][0]], size[ch[x][1]]);}
void insert(int &x, int y) {
if(!x) {
x = y;
update(x);
return;
}
if(t[y].a[d[x]] <= t[x].a[d[x]]) insert(ch[x][0], y);
else insert(ch[x][1], y);
update(x);
if(bad(x)) rebuild(x);
}
int lastans = 0, X, Y, XX, YY;
void query(int x) {
if(!x || ma[x][0] < X || mi[x][0] > XX || ma[x][1] < Y || mi[x][1] > YY) return ;
if(X <= mi[x][0] && ma[x][0] <= XX && Y <= mi[x][1] && ma[x][1] <= YY) {lastans += sum[x]; return;}
if(X <= t[x].a[0] && t[x].a[0] <= XX && Y <= t[x].a[1] && t[x].a[1] <= YY) lastans += f[x];
query(ch[x][0]), query(ch[x][1]);
}
int n;
int main() {
scanf("%d", &n);
while(1) {
int opt;
scanf("%d", &opt);
if(opt == 3) return 0;
if(opt == 1) {
++ tot;
scanf("%d%d%d", &t[tot].a[0], &t[tot].a[1], &f[tot]);
t[tot].a[0] ^= lastans, t[tot].a[1] ^= lastans, f[tot] ^= lastans;
insert(root, tot);
} else {
scanf("%d%d%d%d", &X, &Y, &XX, &YY);
X ^= lastans, Y ^= lastans, XX ^= lastans, YY ^= lastans;
lastans = 0;
query(root);
printf("%d\n", lastans);
}
}
return 0;
}
然后就没了,真是一个神奇的数据结构啊!!!
啊啊啊♂
当然树套树和cdq嵌套也是必须要掌握的呢