zoukankan      html  css  js  c++  java
  • CF1051F The Shortest Statement

    题目大意:给定一张(n)个点(m)条有权边的无向联通图,(q)次询问两点间的最短路

    (nle100000),(mle100000),(1le100000),(m)-(nle20).

    输入样例#1:

    3 3
    1 2 3
    2 3 1
    3 1 5
    3
    1 2
    1 3
    2 3

    输出样例#1:

    3
    4
    1

    输入样例#2:

    8 13
    1 2 4
    2 3 6
    3 4 1
    4 5 12
    5 6 3
    6 7 8
    7 8 7
    1 4 1
    1 8 3
    2 6 9
    2 7 1
    4 6 3
    6 8 2
    8
    1 5
    1 7
    2 3
    2 8
    3 7
    3 4
    6 8
    7 8

    输出样例#2:

    7
    5
    6
    7
    7
    1
    2
    7


    一看到非树边最多只有21条就想到跟非树边有关系

    然后做法十分的暴力

    就是在图中随便找一棵树

    并标记其他的非树边所连接的点

    这样的点最多只有42个

    所以就暴力处理出这些点到其他点的最短路

    然后查询的时候就先查只走树边的距离

    然后暴力查询其他非树点到((u,v))的路径长度

    因为如果(dis(u,v))的路径比只走树边更短

    那么一定经过了非树点

    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    # define int long long
    const int M = 100005 ;
    using namespace std ;
    inline int read() {
    	char c = getchar() ; int x = 0 , w = 1 ;
    	while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
    	while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
    	return x*w ;
    }
    
    int n , m ;
    int hea[M] , num ;
    int fa[M][25] , f[M] , dep[M] , cnt ;
    int dis[45][M] ;
    bool vis[M] , IsN[M] ;
    struct Node { int Id , dis ; };
    struct E {
    	int Nxt , to , dis ;
    } edge[M << 2] ;
    inline bool operator < (Node a , Node b) { return a.dis > b.dis ; }
    inline void add_edge(int from , int to , int dis) {
    	edge[++num].Nxt = hea[from] ; edge[num].to = to ;
    	edge[num].dis = dis ; hea[from] = num ;
    }
    void dye(int u , int father , int depth) {
    	vis[u] = true ;
    	for(int i = hea[u] ; i ; i = edge[i].Nxt) {
    		int v = edge[i].to ;
    		if(v == father) continue ;
    		if(vis[v]) IsN[u] = IsN[v] = true ;
    		else {
    			fa[v][0] = u ;  dep[v] = dep[u] + 1 ; f[v] = f[u] + edge[i].dis ;
    			dye(v , u , depth + 1) ; 
    		}
    	}
    }
    inline void ST() {
    	for(int j = 1 ; j <= 18 ; j ++)
    	    for(int i = 1 ; i <= n ; i ++)
    	        fa[i][j] = fa[fa[i][j - 1]][j - 1] ;
    }
    inline void dijkstra(int t , int S) {
    	memset(vis , false , sizeof(vis)) ;
    	memset(dis[t] , 63 , sizeof(dis[t])) ; dis[t][S] = 0 ;
        priority_queue < Node > q ; q.push((Node) { S , 0 }) ;
        while(!q.empty()) {
        	int u = q.top().Id ; q.pop() ;
        	if(vis[u]) continue ; vis[u] = true ;
        	for(int i = hea[u] ; i ; i = edge[i].Nxt) {
        		int v = edge[i].to ;
        		if(dis[t][v] > dis[t][u] + edge[i].dis) {
        			dis[t][v] = dis[t][u] + edge[i].dis ;
        			if(!vis[v]) q.push((Node) { v , dis[t][v] }) ;
    			}
    		}
    	}
    }
    inline int LCA(int u , int v) {
    	if(dep[u] < dep[v]) swap(u , v) ;
    	for(int i = 18 ; i >= 0 ; i --)
    	    if(dep[fa[u][i]] >= dep[v])
    	        u = fa[u][i] ;
    	if(u == v) return u ;
    	for(int i = 18 ; i >= 0 ; i --)
    		if(fa[u][i] != fa[v][i])
    			u = fa[u][i] , v = fa[v][i] ;
    	return fa[u][0] ;
    }
    # undef int
    int main() {
    # define int long long
    	n = read() ; m = read() ;
    	for(int i = 1 , u , v , w ; i <= m ; i ++) {
    		u = read() , v = read() , w = read() ;
    		add_edge(u , v , w) ; add_edge(v , u , w) ;
    	}
    	fa[1][0] = 1 ; dye(1 , 1 , 1) ;  ST() ;
    	for(int i = 1 ; i <= n ; i ++) if(IsN[i]) 
    	    dijkstra(++cnt , i) ;
    	int q = read() , u , v , Ans ;
    	while(q -- ) {
    		u = read() , v = read() ;
    		Ans = f[u] + f[v] - (f[LCA(u , v)] << 1) ;
    		for(int i = 1 ; i <= cnt ; i ++) Ans = min(Ans , dis[i][u] + dis[i][v]) ;
    	    printf("%lld
    ",Ans) ;
    	}
    	return 0 ;
    }
    
  • 相关阅读:
    重写Override和重加载Overload
    Java 继承
    poj 3263 Tallest Cow
    矩阵求和
    全排列
    最大乘积
    三角形面积
    Sum
    搭积木
    调手表
  • 原文地址:https://www.cnblogs.com/beretty/p/9688187.html
Copyright © 2011-2022 走看看