HDU-6393 Traffic Network in Numazu

題意:給你一個n邊n點的無向連通圖,兩個操做,操做一改變某個邊的權值,操做二查詢某兩個點之間的路徑長度。c++

題解:隨便刪掉環上一條邊搞一棵樹出來,由於兩點間距離是兩點各自到根的距離之和減去2*lca兩點到根的距離。數組

           因此修改操做就變爲維護點到根這條鏈上的權值,差分一下 採用樹狀數組維護。spa

           查詢的時候就是用刪掉那條邊和不用兩種狀況,比較一下大小就行了。code

#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); } } } }
相關文章
相關標籤/搜索