zoukankan      html  css  js  c++  java
  • [SDOI2010]Hide and Seek

    题目

    非常显然就是求一下距离每一个点曼哈顿距离最近的点和最远的点就好了

    最远点非常好算,我们建完(kd-tree)之后直接暴力就好了

    找最近点的时候会有这样一个问题,就是自己找到了自己

    所以我们需要像线段树那样,做一个单点修改,找到那个点的位置,把那个点的坐标修改成((inf,inf)),之后再查询就好了

    代码

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define re register
    #define LL long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    inline int read() {
    	char c=getchar();int x=0;while(c<'0'||x>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    const int maxn=1e5+5;
    const int inf=600000005;
    int mx[maxn][2],mi[maxn][2],id[maxn],l[maxn],r[maxn],fa[maxn],pos[maxn],Ans[maxn];
    struct Point{int x[2],rk;}p[maxn],a[maxn];
    int n,op,cnt,ans;
    inline int cmp(Point A,Point B) {return A.x[op]<B.x[op];}
    inline void pushup(int k) {
    	mx[k][0]=mi[k][0]=p[id[k]].x[0];
    	mx[k][1]=mi[k][1]=p[id[k]].x[1];
    	for(re int i=0;i<2;i++) {
    		if(l[k]) mx[k][i]=max(mx[k][i],mx[l[k]][i]),
    				 mi[k][i]=min(mi[k][i],mi[l[k]][i]);
    		if(r[k]) mx[k][i]=max(mx[k][i],mx[r[k]][i]),
    				 mi[k][i]=min(mi[k][i],mi[r[k]][i]);
    	}
    }
    int build(int x,int y,int o,int f) {
    	if(x>y) return 0;
    	int mid=x+y>>1,k=++cnt;
    	op=o,std::nth_element(p+x,p+mid,p+y+1,cmp);
    	id[k]=mid,pos[p[mid].rk]=k;fa[k]=f;
    	l[k]=build(x,mid-1,o^1,k),r[k]=build(mid+1,y,o^1,k);
    	pushup(k);return k;
    }
    inline int dis(Point A,Point B) {
    	return abs(A.x[0]-B.x[0])+abs(A.x[1]-B.x[1]);
    }
    inline int getmax(Point A,int k) {
    	int res=0;
    	for(re int i=0;i<2;i++) {
    		int a=abs(A.x[i]-mx[k][i]),b=abs(A.x[i]-mi[k][i]);
    		res+=max(a,b);
    	}
    	return res;
    }
    void ask(Point A,int k) {
    	int d=dis(A,p[id[k]]);
    	ans=max(ans,d);
    	int dl=-inf,dr=-inf;
    	if(l[k]) dl=getmax(A,l[k]);
    	if(r[k]) dr=getmax(A,r[k]);
    	if(dl>dr) {
    		if(dl>ans) ask(A,l[k]);
    		if(dr>ans) ask(A,r[k]);
    	}
    	else {
    		if(dr>ans) ask(A,r[k]);
    		if(dl>ans) ask(A,l[k]);
    	}
    }
    inline void change(int k,int x) {
    	id[k]=x;pushup(k);k=fa[k];
    	while(k) {pushup(k);k=fa[k];}
    }
    inline int getmin(Point A,int k) {
    	int res=0;
    	for(re int i=0;i<2;i++) {
    		if(A.x[i]>=mi[k][i]&&A.x[i]<=mx[k][i]) continue;
    		if(A.x[i]<mi[k][i]) res+=mi[k][i]-A.x[i];
    			else if(A.x[i]>mx[k][i]) res+=A.x[i]-mx[k][i];
    	}
    	return res;
    }
    void query(Point A,int k) {
    	int d=dis(A,p[id[k]]);
    	ans=min(ans,d);
    	int dl=inf,dr=inf;
    	if(l[k]) dl=getmin(A,l[k]);
    	if(r[k]) dr=getmin(A,r[k]);
    	if(dl<dr) {
    		if(dl<ans) query(A,l[k]);
    		if(dr<ans) query(A,r[k]);
    	}
    	else {
    		if(dr<ans) query(A,r[k]);
    		if(dl<ans) query(A,l[k]);
    	}
    }
    int main() {
    	n=read();
    	for(re int i=1;i<=n;i++) p[i].x[0]=read(),p[i].x[1]=read(),p[i].rk=i;
    	for(re int i=1;i<=n;i++) a[i]=p[i];
    	build(1,n,0,0);p[n+1].x[0]=p[n+1].x[1]=inf;
    	for(re int i=1;i<=n;i++) 
    		ans=0,ask(a[i],1),Ans[i]=ans;
    	for(re int i=1;i<=n;i++) {
    		int pre=id[pos[i]];
    		change(pos[i],n+1);
    		ans=inf,query(a[i],1),Ans[i]-=ans;
    		change(pos[i],pre);
    	}
    	ans=inf;
    	for(re int i=1;i<=n;i++) ans=min(ans,Ans[i]);
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    HDU1294 Rooted Trees Problem(整数划分 组合数学 DP)
    HDU2546 饭卡(背包)
    经典动态规划总结
    POJ1285 Combinations, Once Again(背包 排列组合)
    计数 组合数学总结
    莫队算法 2038: [2009国家集训队]小Z的袜子(hose)
    循环-24. 求给定序列前N项和之二
    循环-23. 找完数
    循环-22. 输出闰年
    循环-21. 求交错序列前N项和
  • 原文地址:https://www.cnblogs.com/asuldb/p/10754984.html
Copyright © 2011-2022 走看看