CF1051F The Shortest Statement Dijkstra + 性质分析

动态询问连通图任意两点间最短路,单次询问.
显然,肯定有一些巧妙地性质(不然你就发明了新的最短路算法了233)
有一点很奇怪:边数最多只比点数多 $20$ 个,那么就可以将这个图看作是一个生成树,上面连了不到 $20$ 条边.
考虑两个点之间地最短路只有两种情况:经过所有只在生成树上的点,或者经过一些连着生成树外的点.
第一个情况非常好求,随便搞一个生成树然后求个距离就行.
对于第二种情况,由于连着生成树外的边的点最多只有 $20$ 个,所以可以对这些点都跑一遍最短路,然后依次枚举即可.
每次询问的复杂度为 $O(log$ $n+20 )$

#include<bits/stdc++.h>       
using namespace std; 
void setIO(string s) {
    string in=s+".in"; 
    freopen(in.c_str(),"r",stdin); 
}   
typedef long long ll; 
const int maxn=100005;        
const ll inf=10000000000000; 
struct Union { 
    int p[maxn];     
    void init() { 
        for(int i=0;i<maxn;++i) p[i]=i;  
    } 
    int find(int x) {
        return p[x]==x?x:p[x]=find(p[x]); 
    } 
    int merge(int x,int y) {
        int a=find(x),b=find(y); 
        if(a==b) return 0; 
        p[a]=b; 
        return 1;  
    }
}ufs; 
struct Edge { 
    int u,v,c;   
}ed[maxn];  
namespace tree { 
    int edges;  
    int val[maxn<<1],hd[maxn],to[maxn<<1],nex[maxn<<1]; 
    int dep[maxn],fa[maxn],top[maxn],siz[maxn],son[maxn];            
    ll dis[maxn];     
    void addedge(int u,int v,int c) { 
        nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,val[edges]=c;        
    }    
    void dfs1(int u,int ff) { 
        fa[u]=ff,dep[u]=dep[ff]+1,siz[u]=1;    
        for(int i=hd[u];i;i=nex[i]) {
            int v=to[i]; 
            if(v==ff) continue; 
            dis[v]=dis[u]+1ll*val[i];                               
            dfs1(v,u), siz[u]+=siz[v]; 
            if(siz[v]>siz[son[u]]) son[u]=v;   
        }
    }
    void dfs2(int u,int tp) {     
        top[u]=tp;         
        if(son[u]) dfs2(son[u],tp); 
        for(int i=hd[u];i;i=nex[i]) {
            int v=to[i]; 
            if(v==fa[u]||v==son[u]) continue; 
            dfs2(v,v);      
        }
    } 
    int LCA(int x,int y) {
        while(top[x]^top[y]) { 
            dep[top[x]] > dep[top[y]] ? x = fa[top[x]] : y = fa[top[y]];  
        } 
        return dep[x] < dep[y] ? x : y;        
    } 
    ll Dis(int x,int y) {
        return dis[x]+dis[y]-(dis[LCA(x,y)]*2);    
    }
};           
namespace Dijkstra {              
    struct Node { 
        ll dis;  int u; 
        Node(ll dis=0,int u=0):dis(dis),u(u){}    
        bool operator<(Node b) const {
            return dis>b.dis;         
        }
    };     
    priority_queue<Node>Q;   
    int edges;        
    int done[maxn], hd[maxn],to[maxn<<1],nex[maxn<<1],val[maxn<<1];   
    ll d[maxn];   
    ll dis[50][maxn];                      
    void addedge(int u,int v,int c) {
        nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,val[edges]=c;     
    }
    void dijkstra(int s,int idd) {                          
        for(int i=0;i<maxn;++i) d[i]=inf,done[i]=0;   
        d[s]=0, dis[idd][s]=0, Q.push(Node(0,s));              
        while(!Q.empty()) {   
            Node e=Q.top(); Q.pop();   
            int u=e.u;         
            if(done[u]) continue;       
            done[u]=1, dis[idd][u]=d[u];                                    
            for(int i=hd[u];i;i=nex[i]) { 
                int v=to[i];    
                if(d[u]+val[i]<d[v]) {     
                    d[v]=d[u]+1ll*val[i];      
                    Q.push(Node(d[v], v));          
                }
            }
        }
    }
}; 
int n,m;  
int mk[maxn],ne[maxn];                  
int main() { 
    // setIO("input");  
    scanf("%d%d",&n,&m);  
    ufs.init(); 
    for(int i=1;i<=m;++i) {
        scanf("%d%d%d",&ed[i].u,&ed[i].v,&ed[i].c);  
        if(ufs.merge(ed[i].u, ed[i].v)) {
            tree::addedge(ed[i].u, ed[i].v, ed[i].c); 
            tree::addedge(ed[i].v, ed[i].u, ed[i].c);                
            mk[i]=1;  
        }  
    }            
    int cnt=0; 
    tree::dfs1(1,0); 
    tree::dfs2(1,1);    
    for(int i=1;i<=m;++i) if(mk[i]==0) ne[ed[i].u]=ne[ed[i].v]=1;       
    for(int i=1;i<=m;++i) Dijkstra::addedge(ed[i].u, ed[i].v, ed[i].c), Dijkstra::addedge(ed[i].v,ed[i].u,ed[i].c);  
    for(int i=1;i<=n;++i) if(ne[i]) ++cnt, Dijkstra::dijkstra(i,cnt);          
    int Q; 
    scanf("%d",&Q); 
    for(int cas=1;cas<=Q;++cas) {
        int u,v; 
        scanf("%d%d",&u,&v);   
        ll ans=tree::Dis(u,v);          
        for(int i=1;i<=cnt;++i) ans=min(ans,Dijkstra::dis[i][u]+Dijkstra::dis[i][v]);      
        printf("%I64d\n",ans);     
    } 
    return 0; 
}

  

posted @ 2019-07-29 16:24  EM-LGH  阅读(159)  评论(0编辑  收藏  举报