BestCoder Round #80 E Road (hdu5669) 【線段樹+分層圖最短路】
阿新 • • 發佈:2019-02-06
題意:中文題
分析:官方題解說的很詳細了這裡就不轉了,關鍵部分已經註釋了
程式碼:
#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; }