zoukankan      html  css  js  c++  java
  • 逛森林

    题目链接

    看到区间连边最短路,考虑优化连边。发现直接重链剖分线段树时空分别是$O(mlog^3n)$和$O(mlog^2n)$的,被卡掉了。考虑树上倍增,用类似ST表的方法优化连边,更优。

    引用别人题解的一段话:优化连边通常就是考虑一种数据结构$S$,这个$S$一般具有分治结构,且$S$的每一个节点都是图上的一个节点。建立一个入$S$和出$S$,其中出$S$的边由分治结构的子区间指向父亲,入$S$的边由父亲指向儿子,边权都为$0$。每次从$[u_1,v_1]$向$[u_2,v_2]$连边时,先新建虚点$T$,在出$S$上提取出$[u_1,v_1]$向$T$连边,在入$S$上提取出$[u_2,v_2]$并从$T$向其连边,容易看出这和暴力连边是等效的。

    读入并连原生树边的同时的维护并查集筛掉不合法的操作。暂时先存起合法的1操作。

    因为这是个森林,我们挨个尝试跑dfs。

    设$f(u,l)$表示点$u$的$2^l$级祖先,$fi(u,l)$和$fo(u,l)$表示 点$u$一直到它的$2^l-1$级祖先构成的长度为$2^l$链 分别在入结构和出结构上的代表节点 对应的图上的点 的编号。那么在入结构里,我们有边$fi(u,l) o fi(u,l-1)$和边$fi(u,l) o fi(f(u,l-1),l-1)$。在出结构里有两条反向的边。特别地,$fi(u,0)=fo(u,0)=u$。

    大概是这么个结构(虚线表示连着相同左端点的其他“结构点”):

    连好了“结构边”,接下来连“额外边”。

    对于树上的路径,先从LCA处切成两条链,然后利用类似ST表的方法连边。设点$u$的$k$级祖先函数$anc(u,k)$,对于长度为$l$的链$(u,fa)$且有$2^tle l< 2^{t+1}$,选出$fi(u,t)$和$fi(anc(u,l-2^t),t)$即可。

    接着跑堆优化Dijkstra求单源最短路。

    图中点的个数:$n$个原生树点、$2nlog n$个结构点和$m$个额外点。

    图中有向边的个数:$4nlog n$条结构边和$8m$条额外边。

    代码(100分):

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<map>
    #include<set>
    #define IL inline
    #define RG register
    #define _1 first
    #define _2 second
    using namespace std;
    const int N=50000;
    const int M=1e6;
    const int L=15;
    const int V=N+2*N*L+M;
    const int E=4*N*L+8*M;
    const int inf=1e9;
    
        int n,m,S;
        
    struct Ufs{
        int f[N+3],sz[N+3];
        
        IL void init(){
            for(int i=1;i<=n;i++){
                f[i]=i;    sz[i]=1;
            }
        }
        
        int find(int x){
            return f[x]==x?x:f[x]=find(f[x]);
        }
        
        IL void merge(int x,int y){
            x=find(x);    y=find(y);
            if(sz[x]<sz[y])    swap(x,y);
            f[y]=x;    sz[x]+=(int)(sz[x]==sz[y]);
        }
        
        IL bool qry(int x,int y){
            return find(x)==find(y);
        }
        
    }ufs;
    
    struct Edge{
        int to,nxt,cap;
    }e[E+3];
        int top,img,h[V+3];
        
    IL void gra_init(){
        top=-1;    img=n;
        memset(h,-1,sizeof h);
        
    }
        
    IL void link(int u,int v,int w){
        top++;
        e[top].to=v;
        e[top].nxt=h[u];
        e[top].cap=w;
        h[u]=top;
        
    }
    
    struct Opt{
        int u1,v1,u2,v2,w;
        Opt(){}
        Opt(int u1,int v1,int u2,int v2,int w)
            :u1(u1),v1(v1),u2(u2),v2(v2),w(w){}
            
    }a[M+3];
        int mm;
        
        int f[N+3][L+3],dep[N+3];
        int fi[N+3][L+3],fo[N+3][L+3];
        
    void dfs(int u,int fr){
        for(int l=1;(1<<l)<=dep[u];l++){
            f[u][l]=f[f[u][l-1]][l-1];
            fi[u][l]=++img;
            fo[u][l]=++img;
            
            link(fi[u][l],fi[u][l-1],0);
            link(fi[u][l],fi[f[u][l-1]][l-1],0);
            link(fo[u][l-1],fo[u][l],0);
            link(fo[f[u][l-1]][l-1],fo[u][l],0);
            
        }
        
        for(int i=h[u];~i;i=e[i].nxt){
            int v=e[i].to;
            if(v==fr||v>n)
                continue;
            
            f[v][0]=u;
            dep[v]=dep[u]+1;
            fi[v][0]=fo[v][0]=v;
            dfs(v,u);
            
        }
        
    }
    
        int lg2[N+3];
        
    IL void lca_init(){
        lg2[1]=0;
        for(int i=2;i<=n;i++)
        if(i==(1<<(lg2[i-1]+1)))
            lg2[i]=lg2[i-1]+1;
        else 
            lg2[i]=lg2[i-1];
        
    }
    
    IL int anc(int u,int k){
        for(int l=lg2[dep[u]];l>=0;l--)
        if((1<<l)<=k){
            u=f[u][l];    k-=1<<l;
        }
        return u;
    }
    
    IL int lca(int x,int y){
        if(dep[x]>dep[y])
            swap(x,y);
        
        y=anc(y,dep[y]-dep[x]);
        if(x==y)
            return x;
        
        for(int l=lg2[dep[x]];l>=0;l--)
        if(f[x][l]!=f[y][l]){
            x=f[x][l];    y=f[y][l];
        }
        return f[x][0];
        
    }
    
    IL void link(int u,int fa,int x,int w,int t){
        int l=dep[u]-dep[fa]+1,k=lg2[l];
        int v=anc(u,l-(1<<k));
        if(t==1){
            link(fo[u][k],x,w);    link(fo[v][k],x,w);
        }
        else {
            link(x,fi[u][k],w);    link(x,fi[v][k],w);
        }
        
    }
        
    struct Dat{
        int v,d;    Dat(){}
        Dat(int v,int d):v(v),d(d){}
    };
    
    IL bool operator<(Dat x,Dat y){
        return x.v>y.v;
    }
    
        int dis[V+3];
        priority_queue<Dat>hp;
        
    IL void dij(int S){
        for(int i=1;i<=img;i++)    dis[i]=inf;
        hp.push(Dat(dis[S]=0,S));
        
        while(!hp.empty()){
            Dat x=hp.top();    hp.pop();
            if(dis[x.d]<x.v)    continue;
            
            int u=x.d;
            for(int i=h[u];~i;i=e[i].nxt){
                int v=e[i].to;
                if(dis[u]+e[i].cap<dis[v])
                    hp.push(Dat(dis[v]=dis[u]+e[i].cap,v));
                
            }
            
        }
        
    }
    
    int main(){
        scanf("%d%d%d",&n,&m,&S);
        ufs.init();
        gra_init();
        mm=0;
        for(int i=1;i<=m;i++){
            int opt;    scanf("%d",&opt);
            if(opt==1){
                int u1,v1,u2,v2,w;
                scanf("%d%d%d%d%d",&u1,&v1,&u2,&v2,&w);
                
                if(ufs.qry(u1,v1)&&ufs.qry(u2,v2))
                    a[++mm]=Opt(u1,v1,u2,v2,w);
                
            }
            else {
                int u,v,w;    scanf("%d%d%d",&u,&v,&w);
                
                if(ufs.qry(u,v))
                    continue;
                ufs.merge(u,v);
                link(u,v,w);
                link(v,u,w);
                
            }
            
        }
        
        memset(dep,0,sizeof dep);
        for(int i=1;i<=n;i++)
        if(!dep[i]){
            f[i][0]=0;
            dep[i]=1;
            fi[i][0]=fo[i][0]=i;
            dfs(i,0);
            
        }
        
        lca_init();
        for(int i=1;i<=mm;i++){
            int ans;    img++;
            ans=lca(a[i].u1,a[i].v1);
            link(a[i].u1,ans,img,0,1);
            link(a[i].v1,ans,img,0,1);
            ans=lca(a[i].u2,a[i].v2);
            link(a[i].u2,ans,img,a[i].w,2);
            link(a[i].v2,ans,img,a[i].w,2);
            
        }
        
        dij(S);
        for(int i=1;i<=n;i++)
        if(dis[i]==inf)
            printf("-1 ");
        else 
            printf("%d ",dis[i]);
    
        return 0;
    
    }
    View Code
  • 相关阅读:
    微信小程序 数组索引 data-“”解释
    Aho-Corasick算法原理(图省事我直接粘贴PPT了)
    神奇的人生
    nginx-学习笔记9
    nginx-学习笔记8
    nginx-学习笔记7
    nginx-学习笔记6
    nginx-学习笔记5
    nginx-学习笔记4
    nginx-学习笔记2
  • 原文地址:https://www.cnblogs.com/Hansue/p/12932652.html
Copyright © 2011-2022 走看看