hdu5669 Road(线段树优化建图+分层图最短路)

题目链接

分析:
又是区间连边,所以考虑用线段树优化建图

dis[i][j] d i s [ i ] [ j ] 表示到点 i i ,飞行了j次的最小距离
dijkstra转移即可

tip

%%%CA爷

看了一下前辈的题解,发现有一种叫做“分层图最短路”的算法
好高大上,实际上就是 dis[i][j] d i s [ i ] [ j ] 的转移(这不是dp吗)。。。orz

WA了。。。拍不出什么错误啊
没招了,想看AC代码的同学们请移步其他blog吧
下面的代码可以用来对拍,但是不能AC(一点用都没有好伐)

求dalao指点
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>

using namespace std;

const int N=500010;
const int M=5000010;
struct node{
    int y,nxt,v;
};
node way[M];
int n,m,K,st[N],tot,cnt,pos[N],INF;
int dis[50005][12];

void add(int u,int w,int z) {
    tot++;way[tot].y=w;way[tot].v=z;way[tot].nxt=st[u];st[u]=tot;
}

void build(int bh,int l,int r) {
    if (l==r) {
        pos[l]=bh;               
        add(bh+4*n,bh,0);             //入树->出树 
        return;
    }
    int mid=(l+r)>>1;
    build(bh<<1,l,mid);
    build(bh<<1|1,mid+1,r);
    int lc=bh<<1,rc=bh<<1|1;
    add(lc,bh,0); add(rc,bh,0); 
    add(bh+4*n,lc+4*n,0);              
    add(bh+4*n,rc+4*n,0);
}

void change(int bh,int l,int r,int L,int R,int w,int opt,int z) {
    if (l>=L&&r<=R) {
        if (!opt) add(bh,w,0);
        else add(w,bh+4*n,z);
        return;
    }
    int mid=(l+r)>>1;
    if (L<=mid) change(bh<<1,l,mid,L,R,w,opt,z);
    if (R>mid) change(bh<<1|1,mid+1,r,L,R,w,opt,z);
}

struct point{
    int u,k,dis;
    point(int uu=0,int kk=0,int d=0) {
        u=uu;k=kk;dis=d;
    }
    bool operator <(const point &b) const {
        return dis>b.dis;
    }
};
priority_queue<point> q;

bool vis[50005][12];

void dijkstra() {
    memset(dis,0x7f,sizeof(dis));
    INF=dis[0][0]; dis[pos[1]][0]=0;
    memset(vis,0,sizeof(vis));
    q.push(point(pos[1],0,0));
    while (!q.empty()) {
        point now=q.top(); q.pop();
        if (vis[now.u][now.k]) continue;
        vis[now.u][now.k]=1;
        int u=now.u,k=now.k;
        for (int i=st[u];i;i=way[i].nxt) {
            int y=way[i].y;
            if (dis[y][k]>dis[u][k]+way[i].v) {
                dis[y][k]=dis[u][k]+way[i].v;
                q.push(point(y,k,dis[y][k]));
            }
            if (k+1<=K&&dis[y][k+1]>dis[u][k]) {
                dis[y][k+1]=dis[u][k];
                q.push(point(y,k+1,dis[y][k+1]));
            }
        }
    }
    int ans=INF;
    for (int i=0;i<=K;i++) ans=min(ans,dis[pos[n]][i]);
    if (ans!=INF) printf("%d\n",ans);
    else printf("CreationAugust is a sb!\n");
}

int main() 
{
    int T;
    scanf("%d",&T);
    while (T--) {
        memset(st,0,sizeof(st));
        tot=0;

        scanf("%d%d%d",&n,&m,&K);
        int a,b,c,d,z;
        build(1,1,n); 
        cnt=n<<3;
        for (int i=1;i<=m;i++) {
            scanf("%d%d%d%d%d",&a,&b,&c,&d,&z);
            change(1,1,n,a,b,++cnt,0,0); change(1,1,n,c,d,cnt,1,z);
            change(1,1,n,c,d,++cnt,0,0); change(1,1,n,a,b,cnt,1,z);
        }

        dijkstra();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值