HDU-6393 Traffic Network in Numazu

题意:给你一个n边n点的无向连通图,两个操作,操作一改变某个边的权值,操作二查询某两个点之间的路径长度。

题解:随便删掉环上一条边搞一棵树出来,因为两点间距离是两点各自到根的距离之和减去2*lca两点到根的距离。

           所以修改操作就变为维护点到根这条链上的权值,差分一下 采用树状数组维护。

           查询的时候就是用删掉那条边和不用两种情况,比较一下大小就好了。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+777;
int E[N],dfn[N],F[N],L[N],R[N],deep[N],inv[N],f[N][20],to[N<<1],w[N<<1],nxt[N<<1],H[N];
int W,X,Y,n,T,m,Q,x,y,z,tar,tot,cnt;
long long C[N];
void add(int u,int v,int z){
    to[tot]=v,w[tot]=z,nxt[tot]=H[u],H[u]=tot++;
}
void dfs(int u,int fa,int deepth){
    dfn[u]=L[u]=++cnt;
    deep[u]=deepth;
    inv[cnt]=u;
    for(int i=H[u];~i;i=nxt[i]){
        int v=to[i];
        if(v==fa) continue;
        if(dfn[v]) {
            tar=(i>>1)+1;
            W=w[i];
            X=u;
            Y=v;
            continue;
        }
        f[v][0]=u;
        F[v]=w[i];
        E[(i>>1)+1]=v;
        dfs(v,u,deepth+1);
    }
    R[u]=cnt;
}
void modify(int u,int v){
    for(;u<=n;u+=u&(-u)) C[u]+=v;
}
long long sum(int u){
    long long ans=0;
    for(;u;u-=u&(-u)) ans+=C[u];
    return ans;
}
void work(){
    for(int i=1;i<20;++i) for(int j=1;j<=n;++j) f[j][i]=f[f[j][i-1]][i-1];
}
int lca(int x,int y){
    if(deep[x]<deep[y]) swap(x,y);
    int dt=deep[x]-deep[y];
    for(int i=0;i<20;++i) if(dt&(1<<i)) x=f[x][i];
    if(x==y) return x;
    for(int i=19;i>=0;--i) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    return f[x][0];
}
long long dist(int x,int y){
    return sum(dfn[x])+sum(dfn[y])-2LL*(sum(dfn[lca(x,y)]));
}
int main(){
    for(scanf("%d",&T);T--;){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i) H[i]=-1,dfn[i]=C[i]=0;
        tot=cnt=0;
        for(int i=1;i<=n;++i){
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z);
            add(y,x,z);
        } 
        dfs(1,0,0);
        work();
        for(int i=1;i<=n;++i) {
            modify(L[inv[i]],F[inv[i]]);
            modify(R[inv[i]]+1,-F[inv[i]]);
        }
        while(m--){
            scanf("%d%d%d",&x,&y,&z);
            if(x==0) {
                if(tar==y) W=z;
                else {
                    int i=E[y];
                    modify(L[i],z-F[i]);
                    modify(R[i]+1,-z+F[i]);
                    F[i]=z;
                }
            }
            else {
                long long ans=dist(y,z);
                ans=min(ans,dist(y,X)+dist(z,Y)+W);
                ans=min(ans,dist(z,X)+dist(y,Y)+W);
                printf("%lld\n",ans);
            }
        }
    }
}

 

posted @ 2018-08-14 01:25 Billyshuai 阅读(...) 评论(...) 编辑 收藏