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); } } } }