P4949 最短距离

P4949 最短距离

神仙黑题

盗图

P4949 最短距离_第1张图片

基环树带修改求距离

1.环上线段树,树上用树剖

代码:(只有90分)

#include
using namespace std;
#define il inline 
const int N=510010;
int n,m;
struct node{
    int from,to,val;
    int expet;
}s[N];
int hed[N]={0},tal[N<<1]={0},val[N<<1]={0},nxt[N<<1]={0},cnt=0;
int fake_fa[N]={0};//假父亲 
int fa[N]={0};//真·父亲 
bool vis[N]={0};
bool flag=0; 
bool is_cir[N]={0};//判断点是否在环上 
int upy=0;
int root[N]={0};
int dep[N]={0};//深度
int size[N]={0};
int son[N]={0}; 
int top[N]={0};
int indexy=0;
int dfn[N]={0};
int rk[N]={0};
int v[N]={0};
int cir_node[N]={0};//环上的点编号 
int anycount=0; 
int belong[N];
int CIR=0;
int ith[N];
int vanu[N]={0};
struct Sugment_Tree{
    int t[N<<2];
    #define mid (l+r)/2
    Sugment_Tree(){
        memset(t,0,sizeof(t));
    }
    il void push_up(int num){
        t[num]=t[num<<1]+t[num<<1|1];
    }
    il void build(int l,int r,int num){
        if(l==r){
            t[num]=v[l];
            return;
        }
        build(l,mid,num<<1);
        build(mid+1,r,num<<1|1);
        push_up(num);
    }    
    il void rebuild(int l,int r,int num){
        if(l==r){
            t[num]=vanu[l];
            return;
        }
        rebuild(l,mid,num<<1);
        rebuild(mid+1,r,num<<1|1);
        push_up(num);
    }    
    il void upd(int l,int r,int num,int pos,int SUM){
        if(l>pos||rreturn;
    //    cout<
        if(l==r){
            t[num]=SUM;
            return;
        }
        upd(l,mid,num<<1,pos,SUM);
        upd(mid+1,r,num<<1|1,pos,SUM);
        push_up(num);
    } 
    il int ask(int l,int r,int num,int L,int R){
        if(l>R||rreturn 0;
        if(l>=L&&r<=R) return t[num];
        return ask(l,mid,num<<1,L,R)+ask(mid+1,r,num<<1|1,L,R);
    }
}T,P;
il void addege(int x,int y,int z){
    cnt++;
    tal[cnt]=y;
    nxt[cnt]=hed[x];
    hed[x]=cnt;
}
il void dfs_find(int x){
    if(is_cir[x]==1) return;
    anycount++;
    cir_node[x]=anycount;
    ith[anycount]=x;
    is_cir[x]=1;
    dfs_find(fake_fa[x]);
}
il void dfs_cir(int u,int fa){
    if(flag==1) return;
    fake_fa[u]=fa;
    vis[u]=1;
    for(int i=hed[u];i;i=nxt[i]){
        int v=tal[i];
        if(v==fa) continue;
        if(vis[v]){
            flag=1;
            dfs_find(u);//导出环 
        } 
        else{
            dfs_cir(v,u);
        }
    }
} 
il void dfs_tree(int u,int fat){
    fa[u]=fat;
    size[u]=1;
    for(int i=hed[u];i;i=nxt[i]){
        int v=tal[i];
        if(v==fat||is_cir[v]) continue;
        dep[v]=dep[u]+1;
        belong[v]=belong[u];
        dfs_tree(v,u);
        size[u]+=size[v];
        if(size[v]>size[son[u]]) son[u]=v;
    }
}
il void dfs2(int u,int tp){
    top[u]=tp;
    ++indexy;
    dfn[u]=indexy;
    rk[dfn[u]]=u;
    if(!son[u]) return;
    dfs2(son[u],tp);
    for(int i=hed[u];i;i=nxt[i]){
        int v=tal[i];
        if(v==fa[u]||v==son[u]||is_cir[v]) continue;
        dfs2(v,v);
    }
}
il int cgn(int x,int y){
    int sum=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        sum+=T.ask(1,n,1,dfn[top[x]],dfn[x]);
        x=fa[top[x]];
    }
    if(dep[x]<dep[y]) swap(x,y);
    sum+=T.ask(1,n,1,dfn[y]+1,dfn[x]);
    return sum;
}
il int kan(int x,int y){
    int sum1=0,sum2=0;
    if(cir_node[x]>cir_node[y]) swap(x,y);
    //y=ith[cir_node[y]-1];
//    cout<//    cout<
    if(cir_node[x]>cir_node[y]-1) return 0;
    sum1=P.ask(1,anycount,1,cir_node[x],cir_node[y]-1);
    //cout<
    sum2=CIR-sum1;
    return min(sum1,sum2);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        s[i].from=x,s[i].to=y,s[i].val=z;
        addege(x,y,z);
        addege(y,x,z);
    }
    dfs_cir(1,1);//找环 
//    for(int i=1;i<=n;i++){//check
//        if(is_cir[i]) printf("%d ",i);
//    }
//    printf("\n");
    //环上的点作为子树的根
    for(int i=1;i<=n;i++){
        if(is_cir[i]){
            belong[i]=i;
            dep[i]=1;
            upy++;
            root[upy]=i;
            dfs_tree(i,i);
        }
    } 
    
//    for(int i=1;i<=n;i++){//check
//        printf("%d ** %d\n",fa[i],son[i]); 
//    }
//    printf("\n");
//    for(int i=1;i<=n;i++){
//        printf("%d ",cir_node[i]);
//    }
//    printf("\n");
    for(int i=1;i<=upy;i++){
        dfs2(root[i],root[i]);
    }
//    cout<//    for(int i=1;i<=n;i++) printf("%d ",dfn[i]);//check
//    printf("\n");
    for(int i=1;i<=n;i++){
        
        if(is_cir[s[i].from]&&is_cir[s[i].to]){
            CIR+=s[i].val;
            if((cir_node[s[i].from]==anycount&&cir_node[s[i].to]==1)||(cir_node[s[i].from]==1&&cir_node[s[i].to]==anycount)){
                continue;
            }
            if(cir_node[s[i].from]>cir_node[s[i].to]){
                s[i].expet=cir_node[s[i].to],vanu[cir_node[s[i].to]]=s[i].val;
            }
            else s[i].expet=cir_node[s[i].from],vanu[cir_node[s[i].from]]=s[i].val;
        }
        else{
            if(fa[s[i].from]==s[i].to) s[i].expet=dfn[s[i].from],v[dfn[s[i].from]]=s[i].val;
            else s[i].expet=dfn[s[i].to],v[dfn[s[i].to]]=s[i].val;
        }
    }
//    for(int i=1;i<=n;i++){
//        cout<//    }
//    cout<
    T.build(1,n,1);
    P.rebuild(1,anycount,1);
//    cout<//cout<
    for(int i=1;i<=m;i++){
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        if(x==1){
            if(is_cir[s[y].from]&&is_cir[s[y].to]){
                CIR-=s[y].val;
                s[y].val=z;
                CIR+=s[y].val;
                if((cir_node[s[y].from]==anycount&&cir_node[s[y].to]==1)||(cir_node[s[y].from]==1&&cir_node[s[y].to]==anycount)){
                    continue;
                }
                //cout<//    cout<
                P.upd(1,anycount,1,s[y].expet,z);
                //cout<
            }
            else{
                T.upd(1,n,1,s[y].expet,z);
            }
        }
        else{
            if(belong[y]==belong[z]){
                printf("%d\n",cgn(y,z));
            }
            else{
                int ans=0;
                ans+=cgn(y,belong[y]);
                ans+=cgn(z,belong[z]);
                //cout<
                ans+=kan(belong[y],belong[z]);
                //cout<
                printf("%d\n",ans);
            }
        }
    } 
    return 0;
    
} 

2.选一条环上的边做特殊边

其余用树剖

代码(100分):

#include
using namespace std;
#define il inline 
const int N=510010;
int n,m;
struct node{
    int from,to,val;
    int expet;
}s[N];
int hed[N]={0},tal[N<<1]={0},val[N<<1]={0},nxt[N<<1]={0},cnt=0;
int fake_fa[N]={0};//假父亲 
int fa[N]={0};//真·父亲 
bool vis[N]={0};
bool flag=0; 
int upy=0;
int root[N]={0};
int dep[N]={0};//深度
int size[N]={0};
int son[N]={0}; 
int top[N]={0};
int indexy=0;
int dfn[N]={0};
int rk[N]={0};
int CIR=0;
int v[N]={0};
int jingzhix,jingzhiy,jingzhival;
struct Sugment_Tree{
    int t[N<<2];
    #define mid (l+r)/2
    Sugment_Tree(){
        memset(t,0,sizeof(t));
    }
    il void push_up(int num){
        t[num]=t[num<<1]+t[num<<1|1];
    }
    il void build(int l,int r,int num){
        if(l==r){
            t[num]=v[l];
            return;
        }
        build(l,mid,num<<1);
        build(mid+1,r,num<<1|1);
        push_up(num);
    }    
    il void upd(int l,int r,int num,int pos,int SUM){
        if(l>pos||rreturn;
    //    cout<
        if(l==r){
            t[num]=SUM;
            return;
        }
        upd(l,mid,num<<1,pos,SUM);
        upd(mid+1,r,num<<1|1,pos,SUM);
        push_up(num);
    } 
    il int ask(int l,int r,int num,int L,int R){
        if(l>R||rreturn 0;
        if(l>=L&&r<=R) return t[num];
        return ask(l,mid,num<<1,L,R)+ask(mid+1,r,num<<1|1,L,R);
    }
}T;
il void addege(int x,int y,int z){
    cnt++;
    tal[cnt]=y;
    nxt[cnt]=hed[x];
    val[cnt]=z;
    hed[x]=cnt;
}
il bool error(int x,int y){
    if(x==jingzhix&&y==jingzhiy) return 1;
    if(x==jingzhiy&&y==jingzhix) return 1;
    return 0;
}
il void dfs_cir(int u,int fa){
    if(flag==1) return;
    fake_fa[u]=fa;
    vis[u]=1;
    for(int i=hed[u];i;i=nxt[i]){
        int v=tal[i];
        if(v==fa) continue;
        if(vis[v]){
            flag=1;
            jingzhix=u;//导出环
            jingzhiy=v;
            jingzhival=val[i]; 
        } 
        else{
            dfs_cir(v,u);
        }
    }
} 
il void dfs_tree(int u,int fat){
    fa[u]=fat;
    size[u]=1;
    for(int i=hed[u];i;i=nxt[i]){
        int v=tal[i];
        if(v==fat) continue;
        if(error(u,v)) continue;
        dep[v]=dep[u]+1;
        dfs_tree(v,u);
        size[u]+=size[v];
        if(size[v]>size[son[u]]) son[u]=v;
    }
}
il void dfs2(int u,int tp){
    top[u]=tp;
    ++indexy;
    dfn[u]=indexy;
    rk[dfn[u]]=u;
    if(!son[u]) return;
    dfs2(son[u],tp);
    for(int i=hed[u];i;i=nxt[i]){
        int v=tal[i];
        if(v==fa[u]||v==son[u]) continue;
        if(error(u,v)) continue;
        dfs2(v,v);
    }
}
il int cgn(int x,int y){
    int sum=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        sum+=T.ask(1,n,1,dfn[top[x]],dfn[x]);
        x=fa[top[x]];
    }
    if(dep[x]<dep[y]) swap(x,y);
    sum+=T.ask(1,n,1,dfn[y]+1,dfn[x]);
    return sum;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        s[i].from=x,s[i].to=y,s[i].val=z;
        addege(x,y,z);
        addege(y,x,z);
    }
    dfs_cir(1,1);//找环 
//    for(int i=1;i<=n;i++){//check
//        if(is_cir[i]) printf("%d ",i);
//    }
//    printf("\n");
    //环上的点作为子树的根
    dep[1]=1;
    upy++;
    root[upy]=1;
    dfs_tree(1,1);
    
    dfs2(1,1);
    for(int i=1;i<=n;i++){
        if(error(s[i].from,s[i].to)) continue;
        if(fa[s[i].from]==s[i].to) s[i].expet=dfn[s[i].from],v[dfn[s[i].from]]=s[i].val;
        else s[i].expet=dfn[s[i].to],v[dfn[s[i].to]]=s[i].val;
    }
    T.build(1,n,1);
    for(int i=1;i<=m;i++){
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        if(x==1){
            if(error(s[y].from,s[y].to)){
                jingzhival=z;
            }
            else{
                T.upd(1,n,1,s[y].expet,z);
            }
        }
        else{
            int ans1=0,ans2=0,ans3=0;
            ans1=cgn(y,z);
            ans2=cgn(y,jingzhix)+cgn(z,jingzhiy)+jingzhival;
            ans3=cgn(y,jingzhiy)+cgn(z,jingzhix)+jingzhival;
            printf("%d\n",min(ans1,min(ans2,ans3)));
        }
    } 
    return 0;
    
} 

 

你可能感兴趣的:(P4949 最短距离)