KD-Tree中的矩形查询

简单模板题:6121. 【GDOI2019模拟2019.4.13】数据结构

首先建树,一层按x二分,一层按y二分交替。
用algorithm中的nth_element(开始,中间,结束(开),比较函数)就可以把点分成两边。但是两边是乱序的。这是线性的.
在这里插入图片描述

然后把每个点控制的矩形区域更新上来,接下来就类似二维线段树了。

据说询问一个矩阵是 O ( n 0.5 ) O(n^{0.5}) O(n0.5)的。证明显然

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=4e5+10;
int n,m;
int opt[N][3],T;
int c[N][2],dep[N];
int a[N];
ll pre[N];

struct point{int x,y;}p[N];
bool operator == (const point &a,const point &b) {
	return a.x == b.x && a.y == b.y;
}
struct node {
	int lx,ly,rx,ry,dep;
	ll v = 0,hismi = 0,tag = 0,mitag=0;
	node(int lxx=0,int lyy=0,int rxx=0,int ryy=0,int d=0){
		lx=lxx,ly=lyy,rx=rxx,ry=ryy,dep=d; 
		v=0,tag=0;
	}
	void tagge(ll vv,ll mi=0){
		mitag = min(mitag, tag + mi);
		tag += vv;
	}
} t[N];

void pushdown(int x){
	if(c[x][0]) t[c[x][0]].tagge(t[x].tag,t[x].mitag);
	if(c[x][1]) t[c[x][1]].tagge(t[x].tag,t[x].mitag);
	t[x].hismi = min(t[x].hismi, t[x].v + t[x].mitag);
	t[x].v += t[x].tag;
	t[x].tag=0;
	t[x].mitag=0;
}

bool cmpx(const point &a,const point &b) {
	return a.x < b.x || a.x == b.x && a.y < b.y;
}

bool cmpy(const point &a,const point &b) {
	return a.y < b.y || a.y == b.y && a.x < b.x;
}

int tot;
int build(int L,int R,int dep){
	int mid=L+R>>1,no=++tot;
	t[no].dep=dep;
	if(L!=R) {
		if(dep&1){
			nth_element(p+L,p+mid,p+R+1,cmpx);
			c[no][0]=build(L,mid,dep+1);
			c[no][1]=build(mid+1,R,dep+1);
		}else{
			nth_element(p+L,p+mid,p+R+1,cmpy);
			c[no][0]=build(L,mid,dep+1);
			c[no][1]=build(mid+1,R,dep+1);
		}
		t[no].lx=min(t[c[no][0]].lx,t[c[no][1]].lx);
		t[no].ly=min(t[c[no][0]].ly,t[c[no][1]].ly);
		t[no].rx=max(t[c[no][0]].rx,t[c[no][1]].rx);
		t[no].ry=max(t[c[no][0]].ry,t[c[no][1]].ry);
	} else {
		t[no]=node(p[mid].x,p[mid].y,p[mid].x,p[mid].y,dep);
	}
	return no;
}

int tlx,trx,tly,ttry;
ll v;

void fz(int vv,int lx,int rx,int ly,int ry){
	v=vv;
	tlx=lx,trx=rx,tly=ly,ttry=ry;
}

#define outof(a,b,c,d) ((b) < (c) || (a) > (d))
void modify(int w){
	if(outof(t[w].lx, t[w].rx, tlx, trx) || outof(t[w].ly, t[w].ry, tly, ttry))return;
	if(tlx <= t[w].lx && t[w].rx <= trx && tly <= t[w].ly && t[w].ry <= ttry) {
		t[w].tagge(v,v);
		return;
	}
	pushdown(w);
	if(c[w][0])modify(c[w][0]);
	if(c[w][1])modify(c[w][1]);
}

ll query(int w,int tx,int ty){
	pushdown(w);
	if(t[w].lx > tx || t[w].rx < tx || t[w].ly > ty || t[w].ry < ty){
		return 0;
	}
	if(t[w].lx == t[w].rx && t[w].ly == t[w].ry){
		return t[w].hismi;
	}
	return min(query(c[w][0],tx,ty),query(c[w][1],tx,ty));
}

int root;
int main(){
	t[0]=node(1e8,1e8,0,0);
	freopen("ds.in","r",stdin);
	freopen("ds.out","w",stdout);
	cin>>n>>m;
	for(int i=1;i<=n;i++)scanf("%d",&a[i]),pre[i]=pre[i-1]+a[i];
	for(int i=1;i<=m;i++){
		for(int j=0;j<3;j++)
			scanf("%d",&opt[i][j]);
		if(opt[i][0]==2){
			p[++T]=(point){opt[i][1],opt[i][2]};
		}else{
			int x = opt[i][1];
			opt[i][2] = opt[i][2] - a[x];
			a[x] += opt[i][2];
		}
	}
	sort(p+1,p+1+T,cmpx);
	T = unique(p+1,p+1+T) - p - 1;
	root = build(1,T,1);
	for(int i=1;i<=m;i++){
		if(opt[i][0] == 1) {
			fz(opt[i][2], 1, opt[i][1], opt[i][1], n);
			modify(root);
		} else {
			printf("%lld\n",pre[opt[i][2]] - pre[opt[i][1] - 1] + query(root, opt[i][1], opt[i][2]));
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值