BestCoder Round #80 E Road (hdu5669) 【线段树+分层图最短路】

链接:http://bestcoder.hdu.edu.cn/contests/contest_chineseproblem.php?cid=688&pid=1005

题意:中文题

分析:官方题解说的很详细了这里就不转了,关键部分已经注释了

代码:

#include <algorithm>
#include <iostream>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <set>
#include <map>
#include <ctime>
#define INF 0x7fffffff
#define Mn 50010*10
#define Mm 2000010
#define mod 1000000007
#define CLR(a,b) memset((a),(b),sizeof((a)))
#define CPY(a,b) memcpy ((a), (b), sizeof((a)))
#pragma comment(linker, "/STACK:102400000,102400000")
#define ul (u<<1)
#define ur ((u<<1)|1)
#define cnt 4*n
using namespace std;
typedef long long ll;
struct edge {
    int v,w,next;
}e[Mm];
struct node {
    int v,cost;
    node(){}
    node(int v,int cost):v(v),cost(cost){}
    bool operator <(const node a) const {
        return a.cost<cost;
    }
};
int tot,head[Mn];
void addedge(int u,int v,int w) {
    e[tot].v=v;
    e[tot].w=w;
    e[tot].next=head[u];
    head[u]=tot++;
}
int tr[Mn],tr2[Mn];
int n,k;
void build(int l,int r,int u) {
    if(l==r) {
        tr[l]=u;
        tr2[l]=cnt+u;//第二棵线段树
        addedge(tr2[l],tr[l],0);//回到第一颗线段树上
        return ;
    }
    int mid=(l+r)>>1;
    build(l,mid,ul);
    build(mid+1,r,ur);
    addedge(ul,u,0);//第一棵线段树中  儿子连向父亲 表示 如果父亲有连向第二棵线段树的边 a b
    addedge(ur,u,0);//则该点可以通过父亲的边连向第二课线段树c d
    addedge(cnt+u,cnt+ul,0);//第二棵线段树中 父亲连向儿子 表示上面节点可以通过该边找到实际的节点 c d
    addedge(cnt+u,cnt+ur,0);
}
int s,t,w,tmp;//tmp为两线段树相连的中间结点
void query(int l,int r,int u) {
    if(s<=l&&t>=r) {
        addedge(u,tmp,0);
        return ;
    }
    int mid=(l+r)>>1;
    if(s<=mid) query(l,mid,ul);
    if(t>mid) query(mid+1,r,ur);
}
void query2(int l,int r,int u) {
    if(s<=l&&t>=r) {
        addedge(tmp,u+cnt,w);
        return ;
    }
    int mid=(l+r)>>1;
    if(s<=mid) query2(l,mid,ul);
    if(t>mid) query2(mid+1,r,ur);
}
priority_queue<node> q;
int dis[Mn][11],vis[Mn][11];
int ans;
void dijkstra(int st,int ed) {
    st=tr[st];ed=tr2[ed];
    while(!q.empty()) q.pop();
    q.push(node(st,0));
    CLR(dis,0x7f);
    CLR(vis,0);
    dis[st][0]=0;
    while(!q.empty()) {
        int v=q.top().v;
        int u=(v-1)%tmp+1;//求出节点和所在层数 这里是为了在优先队列里少存一个数
        int x=(v-u)/tmp;
        q.pop();
        if(vis[u][x]) continue;
        vis[u][x]=1;
        for(int i=head[u];~i;i=e[i].next) {
            int v=e[i].v;
            int cost=e[i].w;
            if(!vis[v][x]&&dis[v][x]>dis[u][x]+cost) {
                dis[v][x]=dis[u][x]+cost;
                q.push(node(v+x*tmp,dis[v][x]));
            }
            if(x<k) {
                if(!vis[v][x+1]&&dis[v][x+1]>dis[u][x]) {
                    dis[v][x+1]=dis[u][x];
                    q.push(node(v+(x+1)*tmp,dis[v][x+1]));
                }
            }
        }
    }
    for(int i=0;i<=k;i++)
        ans=min(ans,dis[ed][i]);
}
void init() {
    tot=0;
    CLR(head,-1);
}
int main() {
    init();
    int m,a,b,c,d;
    scanf("%d",&n);
    scanf("%d%d%d",&n,&m,&k);
    build(1,n,1);
    tmp=cnt*2;
    for(int i=0;i<m;i++) {
        scanf("%d%d%d%d%d",&a,&b,&c,&d,&w);
        tmp++;s=a;t=b;
        query(1,n,1);
        s=c;t=d;
        query2(1,n,1);
        tmp++;
        query(1,n,1);  //边是双向的
        s=a;t=b;
        query2(1,n,1);
    }
    ans=INF;
    dijkstra(1,n);
    if(ans>=INF) printf("CreationAugust is a sb!\n");
    else printf("%d\n",ans);
    return 0;
}


你可能感兴趣的:(BestCoder Round #80 E Road (hdu5669) 【线段树+分层图最短路】)