BZOJ2716 天使玩偶
? 解题记录 ? ? BZOJ ? ? KD tree ?    2017-07-21 10:06:08    505    0    0

2716: [Violet 3]天使玩偶


Description

Input

Output

 

        终于,第一棵KDtree ,撒花~~~撒花~~~撒花~~~

       才知道这道题用4个CDQ容斥不是一般的快,但是80SEC的时间限制给kdtree亮了绿灯!

       主要思想先把所有操作离线,对包括所有插入节点的点集建树,把出现的点做一个exist

       标记,不出现的点先不初始化,也就是不用它的信息来pushup但是需要传递子树信息,

        然后对于每一个插入操作的节点记下树上位置,处理到插入操作直接初始化节点,exist=1就好了。

       主要就是build函数非常坑,另外就是查询操作要留心

#include<cstdio>
#include<algorithm>
#include<cmath>
/*BZOJ2716 离线操作 对拍成功*/
using namespace std;
const int maxn=5e5+100;
const int inf=0x3f3f3f3f;
int opt[maxn*2][3];
int id[maxn*2];
int n,m;
namespace KD_tree{
    struct node{
        int ch[2],mn[2],mx[2],x,y,fa,id;
        bool d,exist;
        node(){mn[0]=mn[1]=inf;exist=0;}
        node(int rx,int ry){x=rx,y=ry;exist=0;}
        void init(){
            mx[0]=mn[0]=x;
            mx[1]=mn[1]=y;
        }
    }tree[maxn*4];
    int cnt,D,root;
     
    bool operator <(const node &a,const node &b){
        return !D?a.y<b.y:a.x<b.x;
    }
     
    void push_up(int rt){
        for(int i=0;i<2;i++)
            for(int j=0;j<2;j++){
                tree[rt].mn[j]=min(tree[rt].mn[j],tree[tree[rt].ch[i]].mn[j]);
                tree[rt].mx[j]=max(tree[rt].mx[j],tree[tree[rt].ch[i]].mx[j]);
            }
    }
     
    void build(int &rt,int l,int r,int d,int fa){
        if(l==r){rt=r;tree[rt].d=d;tree[rt].fa=fa;tree[rt].d=d;return;}
        int mid=(l+r)/2;
        rt=mid;D=d;        /*这里的细节问题一定要注意啊,要不然直接WA+TLE双喜临门*/
        nth_element(tree+l,tree+mid,tree+r+1);
        tree[rt].d=d;tree[rt].fa=fa;
        if(l<mid) build(tree[rt].ch[0],l,mid-1,d^1,rt);
        if(r>mid) build(tree[rt].ch[1],mid+1,r,d^1,rt);
        push_up(rt);
    }
     
    int dis(int x,int y,node rect){
        int tmp=0;
        tmp+=max(0,rect.mn[0]-x),tmp+=max(0,x-rect.mx[0]);
        tmp+=max(0,rect.mn[1]-y),tmp+=max(0,y-rect.mx[1]);
        return tmp;
    }
     
    int mh(int x,int y,int _x,int _y){
        return abs(x-_x)+abs(y-_y);
    }
     
    void query(int x,int y,int rt,int &ans){
        int d,dl=inf,dr=inf;
        if(tree[rt].exist){
            d=mh(x,y,tree[rt].x,tree[rt].y);
            ans=min(d,ans);
        }
        if(tree[rt].ch[0]) dl=dis(x,y,tree[tree[rt].ch[0]]);
        if(tree[rt].ch[1]) dr=dis(x,y,tree[tree[rt].ch[1]]);
        if(dl<dr){
            if(dl<ans) query(x,y,tree[rt].ch[0],ans);
            if(dr<ans) query(x,y,tree[rt].ch[1],ans);
        }else{
            if(dr<ans) query(x,y,tree[rt].ch[1],ans);    
            if(dl<ans) query(x,y,tree[rt].ch[0],ans);        
        }
    }
     
    void insert(int now){
        /* 注意,当前节点一旦插入,需要初始化,并且用该节点信息重新更新整条链 */
        now=id[now];
        tree[now].init();
        tree[now].exist=1;
        while(tree[now].fa){
            push_up(now);
            now=tree[now].fa;
        }
    }
}
 
int main(){
    using namespace KD_tree;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&tree[i].x,&tree[i].y);
        tree[i].exist=1;
        tree[i].init();
    }
    cnt=n;
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&opt[i][0],&opt[i][1],&opt[i][2]);
        if(opt[i][0]==1)    /*未插入的节点仍然需要传递下层信息,只是不传递本身信息*/
            tree[++cnt].x=opt[i][1],tree[cnt].y=opt[i][2],tree[cnt].id=i;
    }
    build(root,1,cnt,1,0);
    for(int i=1;i<=cnt;i++)
        if(tree[i].id) id[tree[i].id]=i;    
    for(int i=1;i<=m;i++){
        int x=opt[i][1],y=opt[i][2],ans=inf;
        if(opt[i][0]==2){
            query(x,y,root,ans);
            printf("%d\n",ans);
        }
        if(opt[i][0]==1)
            insert(i);
    }
    return 0;
}

    P.S. 另外,下面是方差划分版+读入优化

#include<cstdio>
#include<algorithm>
#include<cmath>
#define pow(x) x*x
#define mh(x,y,rect) (abs(rect.pos[0]-x)+abs(rect.pos[1]-y))
using namespace std;
const int maxn=1e6+100;
const int inf=0x3f3f3f3f;
int id[maxn];
int opt[maxn][3];
int n,m;

int read(){
	char c=getchar();int ret=0;
	while(c<'0' || c>'9')
		c=getchar();
	while(c>='0' && c<='9')
		ret=ret*10+c-'0',c=getchar();
	return ret;
}

namespace KD_tree{
	struct node{
		int ch[2],mn[2],mx[2],pos[2],d,id,fa,exist;
		node(){mn[0]=mn[1]=inf;}
		void init(){for(int i=0;i<2;i++) mn[i]=mx[i]=pos[i];}
	}tree[maxn*2];
	int D,cnt=0,root;
	
	bool operator <(const node &a,const node &b){
		return a.pos[D]<b.pos[D];
	}
	
	long long Variance(int l,int r,bool type){
		long long a=0,b=0,n=(r-l+1);
		for(int i=l;i<=r;i++){
			a+=1LL*pow(tree[i].pos[type]);
			b+=1LL*tree[i].pos[type];
		}
		return a/n-pow(b/n);
	}
	
	void push_up(int rt){
		for(int i=0;i<2;i++)
			for(int j=0;j<2;j++){
				tree[rt].mn[j]=min(tree[tree[rt].ch[i]].mn[j],tree[rt].mn[j]);
				tree[rt].mx[j]=max(tree[tree[rt].ch[i]].mx[j],tree[rt].mx[j]);
			}
	}
	
	bool judge(int l,int r){
		long long _x=0,_y=0;
		_x=Variance(l,r,0);
		_y=Variance(l,r,1);
		return _x<_y;
	}
	
	int dis(int x,int y,node rect){
		int tmp=0;
		tmp+=max(x-rect.mx[0],max(rect.mn[0]-x,0));
		tmp+=max(y-rect.mx[1],max(rect.mn[1]-y,0));
		return tmp;
	}
	
	void build(int &rt,int l,int r,int fa){
		if(l==r){rt=l;tree[l].fa=fa;return;}
		int mid=(l+r)/2;
		rt=mid;D=judge(l,r);
		nth_element(tree+l,tree+mid,tree+r+1);
		tree[rt].d=D;tree[rt].fa=fa;
		if(l<mid) build(tree[rt].ch[0],l,mid-1,rt); /*注意这里不要手贱*/
		if(r>mid) build(tree[rt].ch[1],mid+1,r,rt);
		push_up(rt);
	}
	
	void query(int rt,int x,int y,int &ans){
		int dl=inf,dr=inf,d;
		if(tree[rt].exist){
			d=mh(x,y,tree[rt]);
			ans=min(d,ans);
		}
		if(tree[rt].ch[0]) dl=dis(x,y,tree[tree[rt].ch[0]]);
		if(tree[rt].ch[1]) dr=dis(x,y,tree[tree[rt].ch[1]]);
		if(dl<dr){
			if(dl<ans) query(tree[rt].ch[0],x,y,ans);
			if(dr<ans) query(tree[rt].ch[1],x,y,ans);
		}else {
			if(dr<ans) query(tree[rt].ch[1],x,y,ans);
			if(dl<ans) query(tree[rt].ch[0],x,y,ans);
		}
	}
	
	void insert(int w){
		w=id[w];
		tree[w].exist=1;
		tree[w].init();
		while(tree[w].fa){
			push_up(w);
			w=tree[w].fa;
		}
	}
}

int main(){
	using namespace KD_tree;
	//freopen("test.in","r",stdin);
	//freopen("test.out","w",stdout); 
	n=read(),m=read();
	for(int i=1;i<=n;i++){
		tree[i].pos[0]=read();
		tree[i].pos[1]=read();
		tree[i].exist=1;
		tree[i].init();
	}
	cnt=n;
	for(int i=1;i<=m;i++){
		opt[i][0]=read();
		opt[i][1]=read();
		opt[i][2]=read();
		if(opt[i][0]==1)	
			tree[++cnt].id=i,tree[cnt].pos[0]=opt[i][1],tree[cnt].pos[1]=opt[i][2];
	}
	build(root,1,cnt,0);
	for(int i=1;i<=cnt;++i)
		if(!tree[i].exist)
			id[tree[i].id]=i;
	for(int i=1;i<=m;++i){
		int x=opt[i][1],y=opt[i][2],ans=inf;
		if(opt[i][0]==2){
			query(root,x,y,ans);
			printf("%d\n",ans);
		}
		if(opt[i][0]==1)
			insert(i);
	}
	//fclose(stdin);
	//fclose(stdout);
	return 0;
}

 

上一篇: 洛谷P3369【模板】普通平衡树(Treap/SBT)

下一篇: BZOJ3673 可持久化并查集

505 人读过
立即登录, 发表评论.
没有帐号? 立即注册
0 条评论
文档导航