题意:给出n个点n条边的无向带权图,再给出两种操作,操作1是将第x条边的边权修改为y,操作2是询问点x到点y的最短路径。
思路:如果是n个点n-1条边,题目就变成了树,修改边权和询问最短路径都可以在树链剖分上直接操作,而添加了一条边后,就在树上形成了一个环。
读入的时候,用并查集判断哪条边是构成那个环的边(我们把这幅图想象成一棵树加上一条边),记录这条边。
对于修改操作,对于树上的边,用树链剖分修改,对于特殊的边,直接修改。
对于查询操作,只需要查询两个点在树上的路径,和两个点通过这条边的路径(这种方法有两个值)哪个最小就可以了。
#include<bits/stdc++.h> #define clr(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; const int maxn=1e5+10; int n,q,head[maxn],tot,u,v,fa[maxn],sc,me[maxn],size[maxn],l[maxn],r[maxn],fin[maxn],son[maxn]; int dep[maxn],top[maxn],hold[maxn]; ll sum[maxn<<2]; ll w,val[maxn]; struct edge{ int u,v,id; ll w; }a[maxn]; vector<edge >ve[maxn]; void init(){ tot=0; for(int i=1;i<=n;i++){ me[i]=i; } for(int i=1;i<=n;i++){ ve[i].clear(); } } int find(int x){ return x==me[x]?x:me[x]=find(me[x]); } void build(int o,int ql,int qr){ if(ql==qr){ sum[o]=val[fin[ql]]; // printf("ql:%d qr:%d sum[o]:%d fin[ql]:%d ",ql,qr,sum[o],fin[ql]); return; } int mid=(ql+qr)>>1; build(o<<1,ql,mid); build(o<<1|1,mid+1,qr); sum[o]=sum[o<<1]+sum[o<<1|1]; } void update(int o,int ql,int qr,int p,int v){ if(ql==qr){ sum[o]=v; return; } int mid=(ql+qr)>>1; if(p<=mid)update(o<<1,ql,mid,p,v); else update(o<<1|1,mid+1,qr,p,v); sum[o]=sum[o<<1]+sum[o<<1|1]; } ll query(int o,int l,int r,int ql,int qr){ if(ql<=l&&r<=qr)return sum[o]; int mid=(l+r)>>1; ll res=0; if(ql<=mid)res+=query(o<<1,l,mid,ql,qr); if(qr>mid)res+=query(o<<1|1,mid+1,r,ql,qr); return res; } inline ll get(int x) { ll ret = 0; while(top[x]!=1) { // printf("top[x]:%d ",top[x]); ret+=query(1,1,n,l[top[x]],l[x]); x=fa[top[x]]; } ret+=query(1,1,n,1,l[x]); return ret; } int lca(int x,int y){ while(top[x]!=top[y]) { if(dep[top[x]]>=dep[top[y]])x=fa[top[x]]; else y=fa[top[y]]; } return dep[x]<dep[y]?x:y; } inline void dfs_1(int x,int pre) { // printf("x:%d pre:%d ",x,pre); fa[x] = pre; son[x] = -1; size[x] = 1; dep[x] = dep[pre]+1; int si=ve[x].size(); for(int i = 0; i < si; i++){ int v=ve[x][i].v; if( v!= pre) { val[v]=ve[x][i].w; hold[ve[x][i].id]=v; dfs_1(v,x); size[x] += size[v]; if(son[x]==-1 || size[v]>size[son[x]]) son[x] = v; } } } inline void dfs_2(int x,int root) { top[x] = root; l[x] = ++tot; fin[l[x]] = x; if(son[x] != -1) dfs_2(son[x],root); int si=ve[x].size(); for(int i = 0; i < si; i++){ int v=ve[x][i].v; if(v != fa[x] && v != son[x]) dfs_2(v,v); } r[x]=tot; } int main(){ int T; cin>>T; while(T--){ scanf("%d%d",&n,&q); init(); for(int i=1;i<=n;i++){ scanf("%d%d%lld",&a[i].u,&a[i].v,&a[i].w); a[i].id=i; int fu=find(a[i].u),fv=find(a[i].v); // printf("u:%d v:%d fu:%d fv:%d ",u,v,fu,fv); if(fu!=fv){ me[fu]=fv; ve[a[i].u].push_back({a[i].u,a[i].v,i,a[i].w}); ve[a[i].v].push_back({a[i].v,a[i].u,i,a[i].w}); }else{ sc=i; } } dfs_1(1,0); // printf("debug "); dfs_2(1,1); build(1,1,n); int op,x,y; while(q--){ scanf("%d%d%d",&op,&x,&y); if(op==0){ if(x==sc){ a[sc].w=y; }else{ update(1,1,n,l[hold[x]],y); } }else{ int lc=lca(x,y); ll ans=get(x)+get(y)-2*get(lc); ll res1=get(x)+get(a[sc].u)-2*(get(lca(x,a[sc].u)))+get(y)+get(a[sc].v)-2*(get(lca(y,a[sc].v))); ll res2=get(x)+get(a[sc].v)-2*(get(lca(x,a[sc].v)))+get(y)+get(a[sc].u)-2*(get(lca(y,a[sc].u))); printf("%lld ",min(ans,a[sc].w+min(res1,res2))); } } } }