• 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
    ",ans);     
        } 
        return 0; 
    }
    

      

  • 相关阅读:
    Docker实践之03-Dockerfile指令详解
    Docker实践之02-使用镜像及定制
    通过Hack方式实现SDC中Stage配置联动刷新
    多级部门查询性能问题解决方案
    Docker实践之01-入门介绍
    从阿里腾讯2朵云产品中学到的用户体验
    HttpClient在多线程环境下踩坑总结
    一次对JDK进行"减肥"的记录
    北京西站如何进站接人
    多实例集群部署下的图片上传和访问
  • 原文地址:https://www.cnblogs.com/guangheli/p/11264598.html
Copyright © 2020-2023  润新知