题目大意:
给定n q
在n个点n条边的图中
进行q次操作
0 k x 为修改第k条边的值为x
1 x y 为查询x到y的最短路
https://blog.csdn.net/nka_kun/article/details/81675119
用其中n-1条边构成一棵树 树链剖分
多出的那条边记录好 编号s 边的两端su sv 边权sw
此时两点间最短路为三种情况取小
树上x到y、树上x到su + 树上y到sv + sw、树上x到sv + 树上y到su + sw
#include <bits/stdc++.h> using namespace std; #define LL long long #define INF 0x3f3f3f3f #define mem(i,j) memset(i,j,sizeof(i)) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define root 1,n,1 const int N=1e5+5; int n,q; struct QTree { struct EDGE { int to,ne; }e[N<<1]; int head[N], tot; void add(int u,int v) { e[tot].to=v; e[tot].ne=head[u]; head[u]=tot++; } int fa[N], son[N], dep[N], num[N]; int top[N], p[N], fp[N], pos; LL sumT[N<<2]; void init() { tot=1; mem(head,0); pos=0; mem(son,0); } // --------------------以下是线段树------------------------- void pushup(int rt) { sumT[rt]=sumT[rt<<1]+sumT[rt<<1|1]; } void build(int l,int r,int rt) { if(l==r) { sumT[rt]=0; return ; } int m=(l+r)>>1; build(lson), build(rson); pushup(rt); } void update(int k,int w,int l,int r,int rt) { if(l==r) { sumT[rt]=w; return; } int m=(l+r)>>1; if(k<=m) update(k,w,lson); else update(k,w,rson); pushup(rt); } LL query(int L,int R,int l,int r,int rt) { if(L<=l && r<=R) return sumT[rt]; int m=(l+r)>>1; LL res=0; if(L<=m) res+=query(L,R,lson); if(R>m) res+=query(L,R,rson); return res; } // --------------------以上是线段树------------------------- // --------------------以下是树链剖分------------------------- void dfs1(int u,int pre,int d) { dep[u]=d; fa[u]=pre; num[u]=1; for(int i=head[u];i;i=e[i].ne) { int v=e[i].to; if(v!=fa[u]) { dfs1(v,u,d+1); num[u]+=num[v]; if(!son[u] || num[v]>num[son[u]]) son[u]=v; } } } void dfs2(int u,int sp) { top[u]=sp; p[u]=++pos; fp[p[u]]=u; if(!son[u]) return; dfs2(son[u],sp); for(int i=head[u];i;i=e[i].ne) { int v=e[i].to; if(v!=son[u] && v!=fa[u]) dfs2(v,v); } } LL queryPath(int x,int y) { LL ans=0; int fx=top[x], fy=top[y]; while(fx!=fy) { if(dep[fx]>=dep[fy]) { ans+=query(p[fx],p[x],root); x=fa[fx]; } else { ans+=query(p[fy],p[y],root); y=fa[fy]; } fx=top[x], fy=top[y]; } if(x==y) return ans; if(dep[x]>dep[y]) swap(x,y); return ans+query(p[son[x]],p[y],root); } // --------------------以上是树链剖分------------------------- void initQTree() { dfs1(1,0,0); dfs2(1,1); build(root); } }T; int E[N][3]; int fa[N]; int getfa(int x) { if(x==fa[x]) return x; else return fa[x]=getfa(fa[x]); } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&q); T.init(); int s,su,sv,sw; for(int i=1;i<=n;i++) fa[i]=i; for(int i=1;i<=n;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); E[i][0]=u, E[i][1]=v, E[i][2]=w; int fu=getfa(u), fv=getfa(v); if(fu==fv) s=i,su=u,sv=v,sw=w; else fa[fu]=fv,T.add(u,v),T.add(v,u); } T.initQTree(); for(int i=1;i<=n;i++) { if(i==s) continue; if(T.dep[E[i][0]]>T.dep[E[i][1]]) swap(E[i][0],E[i][1]); T.update(T.p[E[i][1]],E[i][2],root); } while(q--) { int op; scanf("%d",&op); if(op==0) { int k,w; scanf("%d%d",&k,&w); if(k==s) sw=w; else T.update(T.p[E[k][1]],w,root); } else { int x,y; scanf("%d%d",&x,&y); LL ans=sw+T.queryPath(x,su)+T.queryPath(sv,y); ans=min(ans,sw+T.queryPath(x,sv)+T.queryPath(y,su)); ans=min(ans,T.queryPath(x,y)); printf("%lld\n",ans); } } } return 0; }