• BZOJ_2716_[Violet 3]天使玩偶&&BZOJ_2648_SJY摆棋子_KDTree


    BZOJ_2716_[Violet 3]天使玩偶&&BZOJ_2648_SJY摆棋子_KDTree

    Description

    这天,SJY显得无聊。在家自己玩。在一个棋盘上,有N个黑色棋子。他每次要么放到棋盘上一个黑色棋子,要么放上一个白色棋子,如果是白色棋子,他会找出距离这个白色棋子最近的黑色棋子。此处的距离是 曼哈顿距离 即(|x1-x2|+|y1-y2|) 。现在给出N<=500000个初始棋子。和M<=500000个操作。对于每个白色棋子,输出距离这个白色棋子最近的黑色棋子的距离。同一个格子可能有多个棋子。

    Input

    第一行两个数 N M
    以后M行,每行3个数 t x y
    如果t=1 那么放下一个黑色棋子
    如果t=2 那么放下一个白色棋子

    Output

    对于每个T=2 输出一个最小距离

    Sample Input

    2 3
    1 1
    2 3
    2 1 2
    1 3 3
    2 4 2

    Sample Output

    1
    2

    HINT


    kdtree可以过


    kdtree是主要处理多维空间信息的工具。

    当k=2时通常用来解决矩形查询问题,已知的一些矩形查询问题复杂度可以证明。

    不过由于kdtree的实质看起来像剪枝,处理其他问题时也有很优越的时间。

    kdtree像是一棵BST,它对于每层找到坐标为中位数的点当做这个点维护的信息,然后递归左右。

    建树时通常横着切一刀竖着切一刀,再用nth_element来保证复杂度。

    每个节点维护子树信息,mx[p][0]和mn[p][0]表示横坐标的范围,纵坐标同理。

    通常插入点的时候要保证平衡而重构kdtree。

    对于这道题我们维护出kdtree的信息。

    查询时面对ls和rs两个矩形,分别求出他们的估价dis,即查询点到两个矩形的曼哈顿最小距离。

    先递归dis小的那个,然后再判断答案和dis的关系决定是否递归另一棵子树。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define N 1000050
    #define ls ch[p][0]
    #define rs ch[p][1]
    #define _min(x,y) ((x)<(y)?(x):(y))
    #define _max(x,y) ((x)>(y)?(x):(y))
    int mx[N][2],mn[N][2],ch[N][2],now,root,ans,n,m,dep[N],maxdep;
    inline char nc() {
    	static char buf[100000],*p1,*p2;
    	return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    int rd() {
    	int x=0; char s=nc();
    	while(s<'0'||s>'9') s=nc();
    	while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+s-'0',s=nc();
    	return x;
    }
    char pbuf[100000],*pp=pbuf;
    void push(const char ch) {
    	if(pp-pbuf==100000) fwrite(pbuf,1,100000,stdout),pp=pbuf;
    	*pp++=ch;
    }
    void write(int x) {
    	static char sta[35];
    	int top=0;
    	do{sta[++top]=x%10,x/=10;}while(x);
    	while(top) push(sta[top--]+'0');
    	push('
    ');
    }
    struct Point {
    	int p[2];
    	bool operator < (const Point &u) const {
    		return p[now]==u.p[now]?p[!now]<u.p[!now]:p[now]<u.p[now]; 
    	}
    }a[N];
    int Abs(int x) {return x>0?x:-x;}
    void pushup(int p,int x) {
    	mx[p][0]=_max(mx[p][0],mx[x][0]);
    	mx[p][1]=_max(mx[p][1],mx[x][1]);
    	mn[p][0]=_min(mn[p][0],mn[x][0]);
    	mn[p][1]=_min(mn[p][1],mn[x][1]);
    }
    int build(int l,int r,int type,int fa) {
    	int mid=(l+r)>>1;
    	dep[mid]=dep[fa]+1;
    	maxdep=_max(maxdep,dep[mid]);
    	now=type;
    	nth_element(a+l,a+mid,a+r+1);
    	mx[mid][0]=mn[mid][0]=a[mid].p[0];
    	mx[mid][1]=mn[mid][1]=a[mid].p[1];
    	if(l<mid) ch[mid][0]=build(l,mid-1,!type,mid),pushup(mid,ch[mid][0]);
    	if(r>mid) ch[mid][1]=build(mid+1,r,!type,mid),pushup(mid,ch[mid][1]);
    	return mid;
    }
    void insert(int x) {
    	int p=root;
    	now=0;
    	while(1) {
    		pushup(p,x);
    		if(a[x].p[now]<a[p].p[now]) {
    			if(ls) p=ls;
    			else {ls=x; pushup(p,x); dep[x]=dep[p]+1; break;}
    		}else {
    			if(rs) p=rs;
    			else {rs=x; pushup(p,x); dep[x]=dep[p]+1; break;}
    		}
    		now=now^1;
    	}
    	maxdep=_max(maxdep,dep[x]);
    	if(maxdep>100) maxdep=0,root=build(1,n,0,0);
    }
    int getdis(int x,int y,int p) {
    	int re=0;
    	if(x<mn[p][0]) re+=mn[p][0]-x;
    	if(x>mx[p][0]) re+=x-mx[p][0];
    	if(y<mn[p][1]) re+=mn[p][1]-y;
    	if(y>mx[p][1]) re+=y-mx[p][1];
    	return re;
    }
    void query(int x,int y,int p) {
    	int re=Abs(x-a[p].p[0])+Abs(y-a[p].p[1]),dl,dr;
    	if(re<ans) ans=re;
    	dl=ls?getdis(x,y,ls):0x3f3f3f3f;
    	dr=rs?getdis(x,y,rs):0x3f3f3f3f;
    	if(dl<dr) {
    		if(dl<ans) query(x,y,ls);
    		if(dr<ans) query(x,y,rs);
    	}else {
    		if(dr<ans) query(x,y,rs);
    		if(dl<ans) query(x,y,ls);
    	}
    }
    int main() {
    	n=rd(); m=rd();
    	int i,opt,x,y;
    	for(i=1;i<=n;i++) a[i].p[0]=rd(),a[i].p[1]=rd();
    	root=build(1,n,0,0);
    	while(m--) {
    		opt=rd(); x=rd(); y=rd();
    		if(opt==1) n++,a[n].p[0]=mx[n][0]=mn[n][0]=x,a[n].p[1]=mx[n][1]=mn[n][1]=y,insert(n);
    		else ans=0x3f3f3f3f,query(x,y,root),write(ans);
    	}
    	fwrite(pbuf,1,pp-pbuf,stdout);
    }
    
  • 相关阅读:
    2020年3月22日
    2021年3月21日
    2021年3月20日
    人件集阅读笔记02
    2021年3月19日
    2021年3月18日
    2021年3月17日
    2021年3月16日
    2021年3月15日
    梦断代码阅读笔记01
  • 原文地址:https://www.cnblogs.com/suika/p/9278769.html
Copyright © 2020-2023  润新知