[BZOJ2125]最短路

题目大意:
  给定一个$n(n\leq10000)$个点的仙人掌,$q$组询问,每次询问两点间的最短路。

思路:
  将仙人掌上问题转化为树上问题。以$1$为根,求出单源最短路。然后选择每个环中深度最小的点作为环的关键点,将原来环中的边删除,并让环中每个点都连向这个关键点,这样原图就变成了一个树。这样两点间距离可以通过LCA求出,最后如果两点路径中连向LCA的两条边在同一条环上,需要特判环上的两种情况。

  1 #include<cstdio>
  2 #include<cctype>
  3 #include<climits>
  4 #include<functional>
  5 #include<ext/pb_ds/priority_queue.hpp>
  6 inline int getint() {
  7     register char ch;
  8     while(!isdigit(ch=getchar()));
  9     register int x=ch^'0';
 10     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
 11     return x;
 12 }
 13 const int N=10001,logN=14,M=40000;
 14 int n,m,sz,dis[N],dep[N],dfn[N],head[N],last[N],cir[N],len[N],dis2[N],anc[N][logN];
 15 struct Edge {
 16     int from,to,w,next;
 17 };
 18 Edge e[M];
 19 inline void add_edge(const int &u,const int &v,const int &w=0) {
 20     e[sz]=(Edge){u,v,w,head[u]},head[u]=sz++;
 21     e[sz]=(Edge){v,u,w,head[v]},head[v]=sz++;
 22 }
 23 struct Vertex {
 24     int id,dis;
 25     bool operator > (const Vertex &another) const {
 26         return dis>another.dis;
 27     }
 28 };
 29 __gnu_pbds::priority_queue<Vertex,std::greater<Vertex> > q;
 30 __gnu_pbds::priority_queue<Vertex,std::greater<Vertex> >::point_iterator p[N];
 31 void dijkstra() {
 32     for(register int i=1;i<=n;i++) {
 33         p[i]=q.push((Vertex){i,dis[i]=i==1?0:INT_MAX});
 34     }
 35     while(!q.empty()) {
 36         const int &x=q.top().id;
 37         for(register int i=head[x];~i;i=e[i].next) {
 38             const int &y=e[i].to,&w=e[i].w;
 39             if(dis[x]+w<dis[y]) {
 40                 q.modify(p[y],(Vertex){y,dis[y]=dis[x]+w});
 41             }
 42         }
 43         q.pop();
 44     }
 45 }
 46 inline int lg2(const float &x) {
 47     return ((unsigned&)x>>23&255)-127;
 48 }
 49 void cut(int x,const int y,const int &id) {
 50     e[id].to=e[id^1].to=0;
 51     len[++cir[0]]=e[id].w;
 52     for(;x!=y;x=e[last[x]].from) {
 53         e[last[x]].to=e[last[x]^1].to=0;
 54         len[cir[x]=cir[0]]+=e[last[x]].w;
 55         add_edge(x,y);
 56     }
 57 }
 58 void dfs(const int &x) {
 59     dfn[x]=++dfn[0];
 60     for(register int i=head[x];~i;i=e[i].next) {
 61         if(i==(last[x]^1)||i>=m*2) continue;
 62         const int &y=e[i].to,&w=e[i].w;
 63         if(!dfn[y]) {
 64             last[y]=i;
 65             dis2[y]=dis2[x]+w;
 66             dfs(y);
 67         } else if(dfn[y]<dfn[x]) {
 68             cut(x,y,i);
 69         }
 70     }
 71 }
 72 void dfs2(const int &x,const int &par) {
 73     dep[x]=dep[anc[x][0]=par]+1;
 74     for(register int i=1;i<=lg2(dep[x]);i++) {
 75         anc[x][i]=anc[anc[x][i-1]][i-1];
 76     }
 77     for(register int i=head[x];~i;i=e[i].next) {
 78         const int &y=e[i].to;
 79         if(y&&y!=par) dfs2(y,x);
 80     }
 81 }
 82 int calc(const int &u,const int &v) {
 83     int x=u,y=v;
 84     if(dep[x]!=dep[y]) {
 85         if(dep[x]<dep[y]) std::swap(x,y);
 86         for(register int i=lg2(dep[x]-dep[y]);~i;i--) {
 87             if(dep[anc[x][i]]>=dep[y]) x=anc[x][i];
 88         }
 89     }
 90     if(x==y) return dis[u]+dis[v]-dis[x]*2;
 91     for(register int i=lg2(dep[x]);~i;i--) {
 92         if(anc[x][i]!=anc[y][i]) {
 93             x=anc[x][i];
 94             y=anc[y][i];
 95         }
 96     }
 97     if(cir[x]&&cir[x]==cir[y]) return dis[u]+dis[v]-dis[x]-dis[y]+std::min(std::abs(dis2[x]-dis2[y]),len[cir[x]]-std::abs(dis2[x]-dis2[y]));
 98     return dis[u]+dis[v]-dis[anc[x][0]]*2;
 99 }
100 int main() {
101     n=getint(),m=getint();
102     const int q=getint();
103     for(register int i=1;i<=n;i++) head[i]=last[i]=-1;
104     for(register int i=0;i<m;i++) {
105         const int u=getint(),v=getint(),w=getint();
106         add_edge(u,v,w);
107     }
108     dijkstra();
109     dfs(1);
110     dfs2(1,0);
111     for(register int i=0;i<q;i++) {
112         printf("%d\n",calc(getint(),getint()));
113     }
114     return 0;
115 }

 

posted @ 2018-03-08 07:59  skylee03  阅读(151)  评论(0编辑  收藏  举报