【HDU】5817 Ice Walls【极角排序+树状数组+最短路】

题目链接:Ice Walls

题目大意:给出平面上一些与坐标轴平行且严格不相交的线段,穿过线段额外花费 k 时间,平面上移动一单位欧式距离花费1,求 s t的最短路。
题目分析:横竖线段分别考虑,先考虑竖线。枚举顶点,求出点和线段到顶点的 x <script type="math/tex" id="MathJax-Element-41">x</script>轴距离,排序,然后双指针,线段覆盖的是一个极角区间,因此可以树状数组求贡献。横线同理。

#include <bits/stdc++.h>
using namespace std ;

typedef long long LL ;
typedef pair < double , int > pii ;

#define clr( a , x ) memset ( a , x , sizeof a )

const int MAXN = 1005 ;
const double eps = 1e-8 ;
const double pi = acos ( -1.0 ) ;

struct Point {
    int x , y ;
    Point () {}
    Point ( int x , int y ) : x ( x ) , y ( y ) {}
    Point operator - ( const Point& a ) const {
        return Point ( x - a.x , y - a.y ) ;
    }
    Point operator + ( const Point& a ) const {
        return Point ( x + a.x , y + a.y ) ;
    }
    void input () {
        scanf ( "%d%d" , &x , &y ) ;
    }
    double angle () {
        return atan2 ( y , x ) ;
    }
    double dis () {
        return sqrt ( 1.0 * x * x + 1.0 * y * y ) ;
    }
} ;

struct Line {
    int u , v ;
} ;

struct Node {
    int dis , idx ;
    bool operator < ( const Node& a ) const {
        return dis < a.dis ;
    }
} ;

Point p[MAXN] ;
Line seg[MAXN] ;
vector < pii > G ;
Node a[MAXN << 1] ;
int n , m , K , s , t ;
int c[MAXN] ;
double dis[MAXN][MAXN] ;
double d[MAXN] ;
int vis[MAXN] ;
int rnk[MAXN] ;

void add ( int x , int n , int v ) {
    for ( int i = x ; i ; i -= i & -i ) {
        c[i] += v ;
    }
}

int sum ( int x , int n ) {
    int ans = 0 ;
    for ( int i = x ; i <= n ; i += i & -i ) {
        ans += c[i] ;
    }
    return ans ;
}

int lfind ( double x , int l = 0 , int r = G.size () - 1 ) {
    while ( l < r ) {
        int m = l + r >> 1 ;
        if ( x + eps < G[m].first ) r = m ;
        else l = m + 1 ;
    }
    if ( x + eps > G[l].first ) ++ l ;
    return l + 1 ;
}

int rfind ( double x , int l = 0 , int r = G.size () - 1 ) {
    while ( l < r ) {
        int m = l + r + 1 >> 1 ;
        if ( G[m].first + eps < x ) l = m ;
        else r = m - 1 ;
    }
    if ( G[l].first + eps > x ) -- l ;
    return l + 1 ;
}

void deal ( int o , int cnt ) {
    int num = G.size () ;
    sort ( G.begin () , G.end () ) ;
    sort ( a , a + cnt ) ;
    for ( int i = 1 ; i <= num ; ++ i ) {
        rnk[G[i - 1].second] = i ;
        c[i] = 0 ;
    }
    for ( int i = 0 ; i < cnt ; ++ i ) {
        int idx = a[i].idx ;
        if ( idx < 0 ) {
            int u = seg[-idx].u ;
            int v = seg[-idx].v ;
            double angl = ( p[u] - p[o] ).angle () ;
            double angr = ( p[v] - p[o] ).angle () ;
            if ( angl > angr ) swap ( angl , angr ) ;
            int l = lfind ( angl ) ;
            int r = rfind ( angr ) ;
            add ( r , num , 1 ) ;
            add ( l - 1 , num , -1 ) ;
        } else {
            LL t = 1LL * K * sum ( rnk[idx] , num ) ;
            dis[o][idx] += t ;
            dis[idx][o] += t ;
        }
    }
}

void dij ( int s ) {
    for ( int i = 1 ; i <= m ; ++ i ) {
        d[i] = dis[s][i] ;
        vis[i] = 0 ;
    }
    d[s] = 0 ;
    vis[s] = 1 ;
    for ( int i = 1 ; i < m ; ++ i ) {
        double minv = 1e60 ;
        int u = s ;
        for ( int j = 1 ; j <= m ; ++ j ) {
            if ( !vis[j] && d[j] < minv ) {
                u = j ;
                minv = d[j] ;
            }
        }
        vis[u] = 1 ;
        for ( int j = 1 ; j <= m ; ++ j ) {
            if ( !vis[j] && d[u] + dis[u][j] < d[j] ) {
                d[j] = d[u] + dis[u][j] ;
            }
        }
    }
}

void solve () {
    m = 0 ;
    scanf ( "%d%d" , &n , &K ) ;
    for ( int i = 1 ; i <= n ; ++ i ) {
        p[++ m].input () ;
        seg[i].u = m ;
        p[++ m].input () ;
        seg[i].v = m ;
    }
    p[++ m].input () ;
    s = m ;
    p[++ m].input () ;
    t = m ;
    for ( int i = 1 ; i <= m ; ++ i ) {
        for ( int j = i + 1 ; j <= m ; ++ j ) {
            dis[i][j] = dis[j][i] = ( p[i] - p[j] ).dis () ;
        }
    }
    for ( int i = 1 ; i <= m ; ++ i ) {
        int cnt = 0 ;
        G.clear () ;
        for ( int j = 1 ; j <= m ; ++ j ) if ( j != i ) {
            if ( p[j].x > p[i].x ) {
                G.push_back ( pii ( ( p[j] - p[i] ).angle () , j ) ) ;
                a[cnt].dis = p[j].x - p[i].x ;
                a[cnt ++].idx = j ;
            }
        }
        for ( int j = 1 ; j <= n ; ++ j ) {
            int x = p[seg[j].u].x ;
            if ( x == p[seg[j].v].x && x > p[i].x ) {
                a[cnt].dis = x - p[i].x ;
                a[cnt ++].idx = -j ;
            }
        }
        deal ( i , cnt ) ;
        cnt = 0 ;
        G.clear () ;
        for ( int j = 1 ; j <= m ; ++ j ) if ( j != i ) {
            if ( p[j].y > p[i].y ) {
                G.push_back ( pii ( ( p[j] - p[i] ).angle () , j ) ) ;
                a[cnt].dis = p[j].y - p[i].y ;
                a[cnt ++].idx = j ;
            }
        }
        for ( int j = 1 ; j <= n ; ++ j ) {
            int y = p[seg[j].u].y ;
            if ( y == p[seg[j].v].y && y > p[i].y ) {
                a[cnt].dis = y - p[i].y ;
                a[cnt ++].idx = -j ;
            }
        }
        deal ( i , cnt ) ;
    }
    dij ( s ) ;
    printf ( "%.10f\n" , d[t] ) ;
}

int main () {
    int T ;
    scanf ( "%d" , &T ) ;
    for ( int i = 1 ; i <= T ; ++ i ) {
        solve () ;
    }
    return 0 ;
}

压缩后代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<double,int>pii;
#define clr(a,x) memset(a,x,sizeof a)
const int MAXN=1005;
const double eps=1e-8;
const double pi=acos(-1.0);
struct Point{
    int x,y;
    Point(){}
    Point(int x,int y):x(x),y(y){}
    Point operator - (const Point &a)const{return Point (x-a.x,y-a.y);}
    Point operator + (const Point &a)const{return Point (x+a.x,y+a.y);}
    void input(){scanf("%d%d",&x,&y);}
    double angle(){return atan2(y,x);}
    double dis(){return sqrt(1.0*x*x+1.0*y*y);}
}p[MAXN];
struct Line{
    int u,v;
}seg[MAXN];
struct Node{
    int dis,idx;
    Node(){}
    Node(int d,int i):dis(d),idx(i){}
    bool operator < (const Node&a)const{return dis<a.dis;}
}a[MAXN<<1];
pii G[MAXN];
int n,m,K,s,t,c[MAXN],vis[MAXN],rnk[MAXN],num;
double dis[MAXN][MAXN],d[MAXN];
void add(int x,int n,int v){
    for(int i=x;i;i-=i&-i)c[i]+=v;
}
int sum(int x,int n,int ans=0){
    for(int i=x;i<=n;i+=i&-i)ans+=c[i];
    return ans;
}
int lfind(double x,int l=0,int r=num-1){
    for(int m=l+r>>1;l<r;m=l+r>>1)x+eps<G[m].first?r=m:l=m+1;
    if(x+eps>G[l].first)++l;
    return l+1;
}
int rfind(double x,int l=0,int r=num-1){
    for(int m=l+r+1>>1;l<r;m=l+r+1>>1)G[m].first+eps<x?l=m:r=m-1;
    if(G[l].first+eps>x)--l;
    return l+1;
}
void deal(int o,int cnt){
    int i,idx;
    sort(G,G+num);
    sort(a,a+cnt);
    for(i=1;i<=num;++i)rnk[G[i-1].second]=i,c[i]=0;
    for(i=0,idx=a[i].idx;i<cnt;++i,idx=a[i].idx){
        if(idx<0){
            int u=seg[-idx].u,v=seg[-idx].v;
            double angl=(p[u]-p[o]).angle();
            double angr=(p[v]-p[o]).angle();
            if(angl>angr)swap(angl,angr);
            int l=lfind(angl),r=rfind(angr);
            add(r,num,1);
            add(l-1,num,-1);
        }else{
            LL t=1LL*K*sum(rnk[idx],num);
            dis[o][idx]+=t;
            dis[idx][o]+=t;
        }
    }
}
void dij(int s){
    int i,j,u;
    for(i=1;i<=m;++i)d[i]=dis[s][i],vis[i]=0;
    for(d[s]=0,vis[s]=1,i=1,j,u;i<m;++i){
        double minv=1e60;
        for(u=s,j=1;j<=m;++j)if(!vis[j]&&d[j]<minv)minv=d[u=j];
        for(vis[u]=1,j=1;j<=m;++j)if(!vis[j]&&d[u]+dis[u][j]<d[j])d[j]=d[u]+dis[u][j];
    }
}
void solve(){
    m=0;
    scanf("%d%d",&n,&K);
    for(int i=1;i<=n;++i)p[seg[i].u=++m].input(),p[seg[i].v=++m].input();
    p[s=++m].input(),p[t=++m].input();
    for(int i=1;i<=m;++i)for(int j=i+1;j<=m;++j)dis[i][j]=dis[j][i]=(p[i]-p[j]).dis();
    for(int i=1,j,cnt;i<=m;++i){
        for(num=0,cnt=0,j=1;j<=m;++j)if(j!=i&&p[j].x>p[i].x){
            G[num++]=pii((p[j]-p[i]).angle(),j);
            a[cnt++]=Node(p[j].x-p[i].x,j);
        }
        for(j=1;j<=n;++j){
            int x=p[seg[j].u].x;
            if(x==p[seg[j].v].x&&x>p[i].x)a[cnt++]=Node(x-p[i].x,-j);
        }
        deal(i,cnt);
        for(num=0,cnt=0,j=1;j<=m;++j)if(j!=i&&p[j].y>p[i].y){
            G[num++]=pii((p[j]-p[i]).angle(),j);
            a[cnt++]=Node(p[j].y-p[i].y,j);
        }
        for(j=1;j<=n;++j){
            int y=p[seg[j].u].y;
            if(y==p[seg[j].v].y&&y>p[i].y)a[cnt++]=Node(y-p[i].y,-j);
        }
        deal(i,cnt);
    }
    dij(s);
    printf("%.10f\n",d[t]);
}
int main(){
    int T;
    scanf("%d",&T);
    for(int i=1;i<=T;++i)solve();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值