zoukankan      html  css  js  c++  java
  • [GX/GZOI2019]特技飞行(扫描线+置换)

    感觉是6题中最难的一题,其实这题是一个二合一:

    第一问:给定平面上若干点和k个关键点,关键点覆盖一个45°倾斜的正方形范围r,求有多少点被至少一个关键点覆盖。这个可以曼哈顿转切比雪夫距离,然后再扫描线求解,复杂度O(nlogn)

    第二问:求最少和最多有多少次擦肩而过。显然每个交点都可以做对向交换,这是最少擦肩而过的次数。最多的次数,假设全部擦肩而过得到排列p,对向交换实际上是交换两元素位置,用最小交换次数还原排列即可。

    #include<bits/stdc++.h>
    using namespace std;
    typedef pair<int,int>pii;
    const int N=5e5+7;
    int n,m,a,b,c,x0,x1,ans1,ans2,tot,cnt,ans,C[N<<1],y[N][2],f[N],vis[N];
    double d[N<<1];
    set<pii>S;
    struct node{double x,y;int v,p;}p[N<<1];
    bool operator<(node a,node b){return a.x<b.x;}
    node calc(int i,int j)
    {
        int y1=y[j][0]-y[i][0],y2=y[i][1]-y[j][1];
        double k=1.0*y1/(y1+y2),xl=1.0*x0+k*(x1-x0),yl=1.0*y[i][0]+k*(y[i][1]-y[i][0]);
        d[++cnt]=xl-yl;
        return(node){xl+yl,xl-yl,0,0};
    }
    bool cmp(node a,node b){return fabs(a.x-b.x)<1e-10?a.y<b.y:a.x<b.x;}
    void add(int x,int v){while(x<=cnt)C[x]+=v,x+=x&-x;}
    int query(int x){int ret=0;while(x)ret+=C[x],x-=x&-x;return ret;}
    bool cmp1(int a,int b){return y[a][1]<y[b][1];}
    int main()
    {
        scanf("%d%d%d%d%d%d",&n,&a,&b,&c,&x0,&x1);
        for(int i=1;i<=n;i++)scanf("%d",&y[i][0]);
        for(int i=1;i<=n;i++)scanf("%d",&y[i][1]);
        for(int i=1;i<=n;i++)
        {
            pii u=make_pair(y[i][1],i);
            set<pii>::iterator it=S.lower_bound(u);
            while(it!=S.end())p[++tot]=calc(it->second,i),it++;
            S.insert(u);
        }
        int sum=tot;scanf("%d",&m);
        for(int i=1,x,y,z;i<=m;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            d[++cnt]=x-y+z,d[++cnt]=x-y-z;
            p[++tot]=(node){x+y+z,x-y+z,1,0};
            p[++tot]=(node){x+y+z,x-y-z,-1,0};
            p[++tot]=(node){x+y-z,x-y+z,-1,0};
            p[++tot]=(node){x+y-z,x-y-z,1,0};
        }
        sort(p+1,p+tot+1);
        sort(d+1,d+cnt+1);
        cnt=unique(d+1,d+cnt+1)-d-1;
        for(int i=1;i<=tot;i++)p[i].p=upper_bound(d+1,d+cnt+1,p[i].y-1e-10)-d;
        sort(p+1,p+tot+1,cmp);
        for(int i=1;i<=tot;i++)if(p[i].v)add(p[i].p,p[i].v);else ans+=query(p[i].p)>0;
        ans1=ans*c+sum*a;
        for(int i=1;i<=n;i++)f[i]=i;
        sort(f+1,f+n+1,cmp1);
        int num=n;
        for(int i=1;i<=n;i++)
        if(!vis[i])
        {
            num--;
            for(int j=i;!vis[j];j=f[j])vis[j]=1;
        }
        ans2=ans1+(b-a)*(sum-num);
        if(ans1>ans2)swap(ans1,ans2);
        printf("%d %d",ans1,ans2);
    }
    View Code
  • 相关阅读:
    ArcEngine连接表join
    坐标系统与投影变换及在ARCGIS中的应用
    ArcEngine 最短路径分析(源码)【转载】
    TOC图例符号转换到ListView
    Dijkstra 最短路径算法的一种高效率实现
    添加、删除连接(Join)和关联(Relate)VBA实例
    C# 实现在线软件自动升级程序
    MapX八个技巧
    希腊字母的读法
    经纬度点与投影坐标系下坐标点的互相转换
  • 原文地址:https://www.cnblogs.com/hfctf0210/p/10859242.html
Copyright © 2011-2022 走看看