BZOJ4066: 简单题【KD树】

题目描述:

N*N的棋盘,初始时每个格子里的数为0,维护两种操作:

命令参数限制内容
1 x y A1<=x,y<=N,A是正整数将格子x,y里的数字加上A
2 x1 y1 x2 y21<=x1<=x2<=N, 1<=y1<=y2<=N输出x1 y1 x2 y2这个矩形内的数字和
3终止程序

强制在线,异或lastans.
1<=N<=500000,操作数不超过200000个,内存限制20M,保证答案在int范围内并且解码之后数据仍合法。

题目分析:

带插入二维数点,然而用平衡因子重构(30000ms)还不如插入5000个点整棵树重构(22000ms)快。。。

Code:

#include<bits/stdc++.h>
#define maxn 200005
using namespace std;
char cb[1<<18],*cs,*ct;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<18,stdin),cs==ct)?0:*cs++)
inline void read(int &a){
	char c;bool f=0;while(!isdigit(c=getc())) c=='-'&&(f=1);
	for(a=c-'0';isdigit(c=getc());a=a*10+c-'0'); f&&(a=-a);	
}
int n,m,rt,tot,id[maxn],*mtp,x[2],y[2],ans;
struct node{
	int d[2],mn[2],mx[2],ch[2],nd,s,x,v;
	void upd(node *t){
		mn[0]=mx[0]=d[0],mn[1]=mx[1]=d[1],s=1,x=v;
		for(int i=0;i<2;i++) if(ch[i]){
			s+=t[ch[i]].s,x+=t[ch[i]].x;
			for(int j=0;j<2;j++) mn[j]=min(mn[j],t[ch[i]].mn[j]),mx[j]=max(mx[j],t[ch[i]].mx[j]);
		}
	}
}t[maxn];
template<int D>bool cmp(int i,int j){return t[i].d[D]<t[j].d[D];}
bool (*fun[2])(int i,int j)={cmp<0>,cmp<1>};
void build(int &i,int l,int r,int D){
	if(l>r) return void(i=0);
	int o=(l+r)>>1;nth_element(id+l,id+o,id+r+1,fun[D]),i=id[o];
	build(t[i].ch[0],l,o-1,D^1),build(t[i].ch[1],o+1,r,D^1);
	t[i].nd=D,t[i].upd(t);
}
void ins(int &i,int x,int D){
	if(!i) {t[i=x].upd(t),t[i].nd=D;return;}
	ins(t[i].ch[fun[D](i,x)],x,D^1),t[i].upd(t);
	if(t[i].s*0.75<max(t[t[i].ch[0]].s,t[t[i].ch[1]].s)) mtp=&i;
}
void pia(int i){
	if(!i) return;
	id[++id[0]]=i,pia(t[i].ch[0]),pia(t[i].ch[1]);
}
void qry(int i){
	if(!i||x[1]<t[i].mn[0]||x[0]>t[i].mx[0]||y[1]<t[i].mn[1]||y[0]>t[i].mx[1]) return;
	if(x[0]<=t[i].mn[0]&&t[i].mx[0]<=x[1]&&y[0]<=t[i].mn[1]&&t[i].mx[1]<=y[1]) {ans+=t[i].x;return;}
	if(x[0]<=t[i].d[0]&&t[i].d[0]<=x[1]&&y[0]<=t[i].d[1]&&t[i].d[1]<=y[1]) ans+=t[i].v;
	qry(t[i].ch[0]),qry(t[i].ch[1]);
}
int main()
{
	read(n);
	int op;
	while(read(op),op<3){
		if(op==1){
			read(x[0]),read(y[0]),t[++tot].d[0]=x[0]^ans,t[tot].d[1]=y[0]^ans;
			read(t[tot].v),t[tot].v^=ans;
			mtp=0,ins(rt,tot,0);
			if(mtp) id[0]=0,pia(*mtp),build(*mtp,1,id[0],t[*mtp].nd);
		}
		else 
			read(x[0]),read(y[0]),read(x[1]),read(y[1]),x[0]^=ans,y[0]^=ans,x[1]^=ans,y[1]^=ans,
			ans=0,qry(rt),printf("%d\n",ans);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值