JZOJ4117. lhxsb

题目描述

这里写图片描述
这里写图片描述
这里写图片描述

20%

暴力搞就行了……
每次用反正切(atan)来搞

100%

水法

cdq分治。
每次按照x来排序,左右各扫一遍。

可以通过感性理解来发现弧度最小的点一定在凸壳
所以分别维护一个上凸壳,之后在上面暴力用叉积判方向即可

code


#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(x,y) (x<y?x:y)
#define max(x,y) (x>y?x:y)
using namespace std;

double x[100001];
double y[100001];
int A[100001][2];
int a[200001][4];
bool bz[100001];
int d[200001];
double ans1[100001];
double ans2[100001];
int i,j,k,l,n,m,len;

inline int getint() { char c; int ret=0; for(c=getchar(); c<'0' || c>'9'; c=getchar()); for(; c>='0'&&c<='9'; c=getchar()) ret=ret*10+c-'0'; return ret; }
void swap(double &a,double &b) {double c=a;a=b;b=c;}
double cross(int i,int j,int k) {return (x[i]-x[k])*(y[j]-y[k])-(x[j]-x[k])*(y[i]-y[k]);}

void qsort(int l,int r)
{
    int i,j;
    double mid;

    i=l;
    j=r;
    mid=x[(l+r)/2];

    while (i<=j)
    {
        while (x[i]<mid) i++;
        while (x[j]>mid) j--;

        if (i<=j)
        {
            swap(x[i],x[j]);
            swap(y[i],y[j]);

            i++,j--;
        }
    }

    if (l<j) qsort(l,j);
    if (i<r) qsort(i,r);

    return;
}

void Qsort(int l,int r)
{
    int i,j,mid,Mid;

    i=l;
    j=r;
    mid=a[(l+r)/2][1];
    Mid=a[(l+r)/2][0];

    while (i<=j)
    {
        while (a[i][1]<mid || a[i][1]==mid && a[i][0]>Mid) i++;
        while (a[j][1]>mid || a[j][1]==mid && a[j][0]<Mid) j--;

        if (i<=j)
        {
            swap(a[i][0],a[j][0]);
            swap(a[i][1],a[j][1]);
            swap(a[i][2],a[j][2]);
            swap(a[i][3],a[j][3]);

            i++,j--;
        }
    }

    if (l<j) Qsort(l,j);
    if (i<r) Qsort(i,r);

    return;
}

double xl(int i,int j)
{
    if (y[i]==y[j]) return 0;
    return (y[j]-y[i])/(x[j]-x[i]);
}

double work(int X,int S,int R)
{
    int L,Mid,MMid;
    double m1,m2,s;

    for (L=R; L>1 && cross(d[L],d[L-1],X)*S<0; L--);

    if (y[d[L]]==y[X])
    s=M_PI_2;
    else
    s=atan(S*(x[X]-x[d[L]])/(y[d[L]]-y[X]));
    if (s<0) s+=M_PI;

    return s;
}

void dg(int l,int r)
{
    int i,j,L,R,Mid,MMid,mid=(l+r)/2;
    double s,m1,m2;

    if (l==r) return;

    dg(l,mid);
    dg(mid+1,r);

    len=0;
    Qsort(l,r);

    fo(i,l,r)
    if (!a[i][0] && a[i][2]<=mid)
    {
        while (len>1 && xl(d[len-1],d[len])<xl(d[len],a[i][1])) len--;
        d[++len]=a[i][1];
    }
    else
    if ( a[i][0] && a[i][2]> mid && len)
    {
        s=work(a[i][1],1,len);
        ans1[a[i][3]]=min(ans1[a[i][3]],s);
    }

    fo(i,l,r-1)
    if (a[i][1]==a[i+1][1] && a[i][0]>a[i+1][0])
    swap(a[i][0],a[i+1][0]),swap(a[i][1],a[i+1][1]),swap(a[i][2],a[i+1][2]),swap(a[i][3],a[i+1][3]);

    len=0;

    fd(i,r,l)
    if (!a[i][0] && a[i][2]<=mid)
    {
        while (len>1 && xl(d[len],d[len-1])>xl(a[i][1],d[len])) len--;
        d[++len]=a[i][1];
    }
    else
    if ( a[i][0] && a[i][2]> mid && len)
    {
        for (R=len; R && d[R]==a[i][1]; R--);

        s=work(a[i][1],-1,R);
        ans2[a[i][3]]=min(ans2[a[i][3]],s);
    }
}

int main()
{
//  freopen("lhxsb2.in","r",stdin);

    n=getint();
    m=getint();
    fo(i,1,n)
    x[i]=getint(),y[i]=getint();

    qsort(1,n);

    fo(i,1,m)
    {
        A[i][0]=getint();
        A[i][1]=getint();
        if (!A[i][0]) bz[A[i][1]]=1;
    }

    j=0;
    fo(i,1,n)
    if (!bz[i])
    {
        j++;
        a[j][0]=0;
        a[j][1]=i;
        a[j][2]=j;
    }

    l=0;
    fd(i,m,1)
    {
        j++;
        a[j][0]=A[i][0];
        a[j][1]=A[i][1];
        a[j][2]=j;

        if (a[j][0])
        {
            l++;
            ans1[l]=233;
            ans2[l]=233;
            a[j][3]=l;
        }
    }
    m=j;

    dg(1,m);

    fd(i,l,1)
    printf("%0.6lf\n",ans1[i]+ans2[i]);

    return 0;
}

正解(伪)

在凸壳上三分
因为是个凸壳,所以可以三分求极值
慢到爆炸
其实一开始是用O2卡过的
没错这是我自己想的SB方法

code


#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(x,y) (x<y?x:y)
#define max(x,y) (x>y?x:y)
using namespace std;

double x[100001];
double y[100001];
int A[100001][2];
int a[200001][4];
bool bz[100001];
int d[200001];
double ans1[100001];
double ans2[100001];
int i,j,k,l,n,m;

inline int getint() { char c; int ret=0; for(c=getchar(); c<'0' || c>'9'; c=getchar()); for(; c>='0'&&c<='9'; c=getchar()) ret=ret*10+c-'0'; return ret; }
void swap(double &a,double &b) {double c=a;a=b;b=c;}

void qsort(int l,int r)
{
    int i,j;
    double mid;

    i=l;
    j=r;
    mid=x[(l+r)/2];

    while (i<=j)
    {
        while (x[i]<mid) i++;
        while (x[j]>mid) j--;

        if (i<=j)
        {
            swap(x[i],x[j]);
            swap(y[i],y[j]);

            i++,j--;
        }
    }

    if (l<j) qsort(l,j);
    if (i<r) qsort(i,r);

    return;
}

void Qsort(int l,int r)
{
    int i,j,mid,Mid;

    i=l;
    j=r;
    mid=a[(l+r)/2][1];
    Mid=a[(l+r)/2][0];

    while (i<=j)
    {
        while (a[i][1]<mid || a[i][1]==mid && a[i][0]>Mid) i++;
        while (a[j][1]>mid || a[j][1]==mid && a[j][0]<Mid) j--;

        if (i<=j)
        {
            swap(a[i][0],a[j][0]);
            swap(a[i][1],a[j][1]);
            swap(a[i][2],a[j][2]);
            swap(a[i][3],a[j][3]);

            i++,j--;
        }
    }

    if (l<j) Qsort(l,j);
    if (i<r) Qsort(i,r);

    return;
}

double xl(int i,int j)
{
    if (y[i]==y[j]) return 0;
    return (y[j]-y[i])/(x[j]-x[i]);
}

double Xl(int i,int j)
{
    if (y[i]==y[j]) return 0;
    return (y[i]-y[j])/(x[j]-x[i]);
}

void dg(int l,int r)
{
    int i,j,L,R,Mid,MMid,mid=(l+r)/2;
    double s,m1,m2;

    if (l==r) return;

    dg(l,mid);
    dg(mid+1,r);

    int len=0;
    Qsort(l,r);

    fo(i,l,r)
    if (!a[i][0] && a[i][2]<=mid)
    {
        while (len>1 && xl(d[len-1],d[len])<xl(d[len],a[i][1])) len--;
        d[++len]=a[i][1];
    }
    else
    if ( a[i][0] && a[i][2]> mid && len)
    {
        L=1;
        R=len;
        while (L<R)
        {
            Mid=(L+R)/2;
            MMid=(Mid+R)/2;

            if (Mid==MMid)
            Mid--,MMid++;

            if (L+1==R)
            Mid=L,MMid=R;

            if (y[d[Mid]]==y[a[i][1]])
            m1=M_PI_2;
            else
            m1=atan((x[a[i][1]]-x[d[Mid]])/(y[d[Mid]]-y[a[i][1]]));
            if (m1<0) m1+=M_PI;

            if (y[d[MMid]]==y[a[i][1]])
            m2=M_PI_2;
            else
            m2=atan((x[a[i][1]]-x[d[MMid]])/(y[d[MMid]]-y[a[i][1]]));
            if (m2<0) m2+=M_PI;

            if (L+1==R)
            {
                if (m1>m2)
                L++; else R--;
                break;
            }

            if (m1<=m2)
            {
                if (R==MMid)
                R--;else R=MMid;
            }
            else
            {
                if (L==Mid)
                L++;else L=Mid;
            }
        }

        if (y[d[L]]==y[a[i][1]])
        s=M_PI_2;
        else
        s=atan((x[a[i][1]]-x[d[L]])/(y[d[L]]-y[a[i][1]]));
        if (s<0) s+=M_PI;

        ans1[a[i][3]]=min(ans1[a[i][3]],s);
    }

    fo(i,l,r-1)
    if (a[i][1]==a[i+1][1] && a[i][0]>a[i+1][0])
    swap(a[i][0],a[i+1][0]),swap(a[i][1],a[i+1][1]),swap(a[i][2],a[i+1][2]),swap(a[i][3],a[i+1][3]);

    len=0;
    fd(i,r,l)
    if (!a[i][0] && a[i][2]<=mid)
    {
        while (len>1 && Xl(d[len],d[len-1])<Xl(a[i][1],d[len])) len--;
        d[++len]=a[i][1];
    }
    else
    if ( a[i][0] && a[i][2]> mid && len)
    {
        L=1;
        for (R=len; R && d[R]==a[i][1]; R--);

        while (L<R)
        {
            Mid=(L+R)/2;
            MMid=(Mid+R)/2;

            if (Mid==MMid)
            Mid--,MMid++;

            if (L+1==R)
            Mid=L,MMid=R;

            if (y[d[Mid]]==y[a[i][1]])
            m1=M_PI_2;
            else
            m1=atan((x[d[Mid]]-x[a[i][1]])/(y[d[Mid]]-y[a[i][1]]));
            if (m1<0) m1+=M_PI;

            if (y[d[MMid]]==y[a[i][1]])
            m2=M_PI_2;
            else
            m2=atan((x[d[MMid]]-x[a[i][1]])/(y[d[MMid]]-y[a[i][1]]));
            if (m2<0) m2+=M_PI;

            if (L+1==R)
            {
                if (m1>m2)
                L++; else R--;
                break;
            }

            if (m1<=m2)
            {
                if (R==MMid)
                R--;else R=MMid;
            }
            else
            {
                if (L==Mid)
                L++;else L=Mid;
            }
        }

        if (y[d[L]]==y[a[i][1]])
        s=M_PI_2;
        else
        s=atan((x[d[L]]-x[a[i][1]])/(y[d[L]]-y[a[i][1]]));
        if (s<0) s+=M_PI;

        ans2[a[i][3]]=min(ans2[a[i][3]],s);
    }
}

int main()
{
    n=getint();
    m=getint();
    fo(i,1,n)
    x[i]=getint(),y[i]=getint();

    qsort(1,n);

    fo(i,1,m)
    {
        A[i][0]=getint();
        A[i][1]=getint();
        if (!A[i][0]) bz[A[i][1]]=1;
    }

    j=0;
    fo(i,1,n)
    if (!bz[i])
    {
        j++;
        a[j][0]=0;
        a[j][1]=i;
        a[j][2]=j;
    }

    l=0;
    fd(i,m,1)
    {
        j++;
        a[j][0]=A[i][0];
        a[j][1]=A[i][1];
        a[j][2]=j;

        if (a[j][0])
        {
            l++;
            ans1[l]=233;
            ans2[l]=233;
            a[j][3]=l;
        }
    }
    m=j;

    dg(1,m);

    fd(i,l,1)
    printf("%0.6lf\n",ans1[i]+ans2[i]);

    return 0;
}

正解

直接二分就ok了
二分判叉积

code

无奇怪的优化


#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(x,y) (x<y?x:y)
#define max(x,y) (x>y?x:y)
using namespace std;

struct BND{int s0,s1,s2,s3;};
struct DDF{double x,y;};

DDF z[100001];
int A[100001][2];
BND a[200001];
bool bz[100001];
int d[200001];
double Xl[200001];
double ans1[100001];
double ans2[100001];
int i,j,k,l,n,m,len;

inline int gt() { char c; int ret=0; for(c=getchar(); c<'0' || c>'9'; c=getchar()); for(; c>='0'&&c<='9'; c=getchar()) ret=ret*10+c-'0'; return ret; }
inline double cross(int i,int j,int k) {return (z[i].x-z[k].x)*(z[j].y-z[k].y)-(z[j].x-z[k].x)*(z[i].y-z[k].y);}
inline void swap(BND &a,BND &b) {BND c=a;a=b;b=c;}

bool cmp(DDF a,DDF b) {return a.x<b.x;}
bool Cmp(BND a,BND b) {return a.s1<b.s1;}

double xl(int i,int j)
{
    if (z[i].y==z[j].y) return 0;
    return (z[j].y-z[i].y)/(z[j].x-z[i].x);
}

double work(int X,int S,int R)
{
    int L,Mid;
    double m1,m2,s;

    L=1;
    R--;
    while (L<R)
    {
        Mid=(L+R)>>1;

        if (cross(d[Mid],d[Mid+1],X)*S<0)
        L=Mid+1; else R=Mid;
    }
    if (L==R && cross(d[L],d[L+1],X)*S<0) L++;

    if (z[d[L]].y==z[X].y)
    s=M_PI_2;
    else
    s=atan(S*(z[X].x-z[d[L]].x)/(z[d[L]].y-z[X].y));
    if (s<0) s+=M_PI;

    return s;
}

void dg(int l,int r)
{
    int i,j,R,Mid,MMid,mid=(l+r)>>1;
    double s,m1,m2;

    if (l==r) return;

    dg(l,mid);
    dg(mid+1,r);

    stable_sort(a+l,a+r+1,Cmp);

    len=0;
    fo(i,l,r)
    if (!a[i].s0 && a[i].s2<=mid)
    {
        while (len>1 && Xl[len-1]<xl(d[len],a[i].s1)) len--;
        d[++len]=a[i].s1;

        if (len>1) Xl[len-1]=xl(d[len-1],d[len]);
    }
    else
    if ( a[i].s0 && a[i].s2> mid && len)
    {
        for (R=len; R && d[R]==a[i].s1; R--);

        if (R)
        {
            s=work(a[i].s1,1,R);
            ans1[a[i].s3]=min(ans1[a[i].s3],s);
        }
    }

    len=0;
    fd(i,r,l)
    if (!a[i].s0 && a[i].s2<=mid)
    {
        while (len>1 && Xl[len-1]>xl(a[i].s1,d[len])) len--; 
        d[++len]=a[i].s1;

        if (len>1) Xl[len-1]=xl(d[len-1],d[len]);
    }
    else
    if ( a[i].s0 && a[i].s2> mid && len)
    {
        for (R=len; R && d[R]==a[i].s1; R--);

        if (R)
        {
            s=work(a[i].s1,-1,R);
            ans2[a[i].s3]=min(ans2[a[i].s3],s);
        }
    }
}

int main()
{
    n=gt();m=gt();
    fo(i,1,n)
    z[i].x=gt(),z[i].y=gt();

    stable_sort(z+1,z+n+1,cmp);

    fo(i,1,m)
    {
        A[i][0]=gt();A[i][1]=gt();
        if (!A[i][0]) bz[A[i][1]]=1;
    }

    j=0;
    fo(i,1,n)
    if (!bz[i])
    {
        j++;
        a[j].s0=0;
        a[j].s1=i;
        a[j].s2=j;
    }

    l=0;
    fd(i,m,1)
    {
        j++;
        a[j].s0=A[i][0];
        a[j].s1=A[i][1];
        a[j].s2=j;

        if (a[j].s0)
        {
            l++;
            ans1[l]=233;
            ans2[l]=233;
            a[j].s3=l;
        }
    }
    m=j;

    dg(1,m);

    fd(i,l,1)
    printf("%0.6lf\n",ans1[i]+ans2[i]);

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值