淺談K-Dtree

前言

發現自己的樹套樹太菜了
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(n21D)\large O(n^{2-\frac{1}{D}}), D是維數

然後來集體練習一下

luogu P4357 [CQOI2016]K遠點對

這題用K-Dtree的時間複雜度是假的
但是可以當作入門題來練練。

K-Dtree有個重要的地方就是方便剪枝
這題就維護子樹範圍內最大最小的橫縱座標,算可能最大的情況作爲估值
比較左右子樹的估值,哪邊估值大就先往哪邊跑。
如果估值<=已知最大的就沒有必要跑了

code;

#include<bits/stdc++.h>
#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<bits/stdc++.h>
#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<bits/stdc++.h>
#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<bits/stdc++.h>
#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<bits/stdc++.h>
#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<bits/stdc++.h>
#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<bits/stdc++.h>
#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嵌套也是必須要掌握的呢

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章