简单题

洛谷

题意:你有一个\(N \times N\)的棋盘,每个格子内有一个整数,初始时的时候全部为 \(0\),现在需要维护两种操作:

- 1 x y A \(1\le x,y\le N\)\(A\) 是正整数。将格子x,y里的数字加上 \(A\)

- 2 x1 y1 x2 y2 \(1 \le x_1 \le x_2 \le N\)\(1 \le y_1\le y_2 \le N\)。输出 \(x_1, y_1, x_2, y_2\) 这个矩形内的数字和

- 3 无 终止程序

分析:学习链接

首先KD-Tree的理论很好理解,就是将一棵树按照某一维度划分成左右子树,然后继续递归分别处理左右子树,选择一个合适的维度作为划分方法,保证树的深度为\(logn\)。上方链接中还提到了本题需要用到的树重构,因为本题操作1相当于在树中新增节点,这样会改变树的结构,可能导致其不平衡,所以设置一个平衡条件来判断当前树是否需要重构。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline int read(){
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
const int N=5e5+5;
const int M=2e4+5;
const int mod=1e9+7;
int n,lastans,tot,rt,t;
int l[N],r[N],d[N],u[N],ls[N],rs[N];
int sum[N],divi[N],size[N],g[N];
struct node{
	int x,y,val;
}a[N];
void update(int p){
	sum[p]=sum[ls[p]]+sum[rs[p]]+a[p].val;
	size[p]=size[ls[p]]+size[rs[p]]+1;
	l[p]=r[p]=a[p].x;d[p]=u[p]=a[p].y;
	if(ls[p]){
		l[p]=min(l[p],l[ls[p]]);r[p]=max(r[p],r[ls[p]]);
		d[p]=min(d[p],d[ls[p]]);u[p]=max(u[p],u[ls[p]]);
	}
	if(rs[p]){
		l[p]=min(l[p],l[rs[p]]);r[p]=max(r[p],r[rs[p]]);
		d[p]=min(d[p],d[rs[p]]);u[p]=max(u[p],u[rs[p]]);
	}
}
bool check(int p){
	double zuo=size[ls[p]]*1.0,you=size[rs[p]]*1.0;
	double lim=0.725*size[p];
	if(zuo>=lim||you>=lim)return true;
	return false;
}
void print(int p){
	if(!p)return;
	print(ls[p]);
	g[++t]=p;
	print(rs[p]);
}
bool cmp1(int x,int y){
	return a[x].x<a[y].x;
}
bool cmp2(int x,int y){
	return a[x].y<a[y].y;
}
int build(int l,int r){
	if(l>r)return 0;
	int mid=(l+r)>>1;
	double avx=0,avy=0,fcx=0,fcy=0;
	for(int i=l;i<=r;++i){
		avx+=a[g[i]].x;avy+=a[g[i]].y;
	}
	avx=avx*1.0/(r-l+1);avy=avy*1.0/(r-l+1);
	for(int i=l;i<=r;++i){
		fcx+=(avx-a[g[i]].x)*(avx-a[g[i]].x);
		fcy+=(avy-a[g[i]].y)*(avy-a[g[i]].y);
	}
	if(fcx>=fcy){
		nth_element(g+l,g+mid,g+r+1,cmp1);
		divi[g[mid]]=1;
	}
	else{
		nth_element(g+l,g+mid,g+r+1,cmp2);
		divi[g[mid]]=2;
	}
	ls[g[mid]]=build(l,mid-1);
	rs[g[mid]]=build(mid+1,r);
	update(g[mid]);
	return g[mid];
}
void rebuild(int& p){
	t=0;
	print(p);
	p=build(1,t);
}
void insert(int& p,int cur){
	if(!p){
		p=cur;
		update(p);
		return;
	}
	if(divi[p]==1){
		if(a[cur].x<=a[p].x)insert(ls[p],cur);
		else insert(rs[p],cur);
	}
	else{
		if(a[cur].y<=a[p].y)insert(ls[p],cur);
		else insert(rs[p],cur);
	}
	update(p);
	if(check(p))rebuild(p);
}
int query(int p,int x1,int y1,int x2,int y2){
	if(!p||x2<l[p]||x1>r[p]||y2<d[p]||y1>u[p])return 0;
	if(l[p]>=x1&&r[p]<=x2&&d[p]>=y1&&u[p]<=y2)return sum[p];
	int cnt=0;
	if(a[p].x>=x1&&a[p].x<=x2&&a[p].y>=y1&&a[p].y<=y2)cnt+=a[p].val;
	return query(ls[p],x1,y1,x2,y2)+query(rs[p],x1,y1,x2,y2)+cnt;
}
int main() {
	n=read();
	while(1){
		int opt=read();
		if(opt==1){
			int x=read(),y=read(),val=read();
			x^=lastans;y^=lastans;val^=lastans;
			a[++tot].x=x;a[tot].y=y;a[tot].val=val;
			insert(rt,tot);
		}
		else if(opt==2){
			int x1=read(),y1=read(),x2=read(),y2=read();
			x1^=lastans;y1^=lastans;x2^=lastans;y2^=lastans;
			lastans=query(rt,x1,y1,x2,y2);
			cout<<lastans<<endl;
		}
		else break;
	}
    return 0; 
}

posted on 2023-03-23 15:55  PPXppx  阅读(27)  评论(0编辑  收藏  举报