bzoj2739 最远点(凸包+决策单调性+分治)

给定一个凸包,询问每个点距离最远的点的标号。
我们按逆时针考虑每一个点i,距离i最远的点j也是在逆时针转的。
因此我们可以把这个凸包拆成链,(把点再复制一次),每个点i合法的点的区间为[i,i+n]。其余点到i的距离为-inf。这样我们就有决策单调性了,随着i的增大j也是单增的。因此我们可以直接分治求。复杂度 O ( n l o g n )

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 500010
inline char gc(){
    static char buf[1<<16],*S,*T;
    if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x*f;
}
int n,ans[N];
inline ll sqr(ll x){return x*x;}
struct P{
    int x,y,id;
    friend ll dis(P a,P b){return sqr(a.x-b.x)+sqr(a.y-b.y);}
}a[N<<1];
inline bool better(int i,int k1,int k2){//k1 is better than k2
    if(k1<i||k1>i+n) return 0;
    if(k2<i||k2>i+n) return 1;
    ll dis1=dis(a[i],a[k1]),dis2=dis(a[i],a[k2]);
    return dis1==dis2?a[k1].id<a[k2].id:dis1>dis2;
}
inline void solve(int l,int r,int L,int R){
    if(l>r) return;int mid=l+r>>1,pos=0;
    for(int i=L;i<=R;++i) if(better(mid,i,pos)) pos=i;
    ans[mid]=pos>n?pos-n:pos;solve(l,mid-1,L,pos);solve(mid+1,r,pos,R);
}
int main(){
//  freopen("a.in","r",stdin);
    int tst=read();
    while(tst--){
        n=read();
        for(int i=1;i<=n;++i) a[i].x=read(),a[i].y=read(),a[i].id=i,a[n+i]=a[i];
        solve(1,n,1,n<<1);
        for(int i=1;i<=n;++i) printf("%d\n",ans[i]);
    }return 0;
}

猜你喜欢

转载自blog.csdn.net/icefox_zhx/article/details/80891169
今日推荐