题意:
一个n个点,n条边的图,2中操作,1是将某条边的权值更改,2是询问两点的最短距离。
题解:
由于n个点,n条边,所以是树加一个环,将环上的边随意取出一条,就是1颗树,以取出的边的一个端点为根,建立有根树。虚线就是取出的边。红色为环上的边。
对于更改边的权值的操作,用dfs序+区间修改点查询的树状树组维护。
对于询问最短路的操作,用LCA分类解决。假设询问的两点是x、y,LCA是 z。
- 若z不是环上的点,那么最短路就是:x到根的距离+y到根的距离-z到根的距离*2;
- 若z是环上的点,最短路可能是经过图中红线的路径,也可能是经过图中虚线的路径,取最短的即可。
代码:
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
#include<cstdio>
#define N 100010
#define INF 0x3f3f3f3f
#define LL long long
#define pb push_back
#define cl clear
#define si size
#define lb lowwer_bound
#define eps 1e-8
#define IO ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define mem(x) memset(x,0,sizeof x )
using namespace std;
int st[N],en[N],fa[N],L[N],a[N],b[N],c[N],e[N],w[N],r[N],anc[N][19],la[N];
int t,n,m,o;
LL d[N];int tt=0;
struct node { int f,s,l;}G[N<<1];
bool fg[N];
inline void add(int u,int v,int id)
{
G[++t].f=v;
G[t].s=id;
G[t].l=la[u];
la[u]=t;
}
void preprocess()
{
for (int i=1;i<=n;i++)
{
anc[i][0]=fa[i];
for (int j=1;(1<<j)<=n;j++) anc[i][j]=-1;
}
for (int j=1;(1<<j)<=n;j++)
for (int i=1;i<=n;i++)
if (anc[i][j-1]!=-1) anc[i][j]=anc[anc[i][j-1]][j-1];
}
int query(int p,int q)
{
int log;
if (L[p]<L[q]) swap(p,q);
for (log=1;(1<<log)<=L[p];log++);log--;
for (int i=log;i>=0;i--)
if (L[p]-(1<<i)>=L[q])p=anc[p][i];
if (p==q)return p;
for (int i=log;i>=0;i--)if (anc[p][i]!=-1 && anc[p][i]!=anc[q][i])
{
p=anc[p][i];
q=anc[q][i];
}
return fa[p];
}
int getfa(int x)
{
return fa[x]==x? x: fa[x]=getfa(fa[x]);
}
void updata(int x,int w)
{
for (;x<N;x+=x&-x) d[x]+=w;
}
LL sum(int x)
{
LL t=0;
for (;x;x-=x&-x) t+=d[x];
return t;
}
void ddfs(int x)
{
st[x]=++t;
for (int i=la[x];i;i=G[i].l)
{
int f=G[i].f,s=G[i].s;
if (fg[f]) continue;
fg[f]=1;
fa[f]=x;
L[f]=L[x]+1;
c[s]=f;
r[f]=w[s];
ddfs(f);
}
en[x]=t;
}
void dfs(int x)
{
for (int i=la[x];i;i=G[i].l)
{
if (L[G[i].f]>L[x] && !e[G[i].f])
{
a[G[i].f]=t;
dfs(G[i].f);
}
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
tt++;
scanf("%d%d",&n,&m);
mem(st);
mem(en);
mem(L);
mem(c);
mem(e);
mem(r);
mem(la);
mem(anc);
mem(G);
mem(d);
mem(fg);
for (int i=1;i<=n;i++) fa[i]=i;
t=0;
for (int i=1;i<=n;i++)
{
scanf("%d%d%d",&a[i],&b[i],&w[i]);
int p=getfa(a[i]),q=getfa(b[i]);
if (p!=q)
{
fa[p]=q;
add(a[i],b[i],i);
add(b[i],a[i],i);
}else o=i;
}
fg[a[o]]=1; t=0; ddfs(a[o]);
LL tot=w[o];
for (int i=1;i<=n;i++) if(i!=a[o])
{
updata(st[i],r[i]);
updata(en[i]+1,-r[i]);
}
fa[a[o]]=0; for (int i=b[o];i;i=fa[i]) e[i]=1,tot+=r[i];
for (int i=1;i<=n;i++) if (e[i])
{
t=i; a[i]=i;
dfs(i);
}
preprocess();
while(m--)
{
int op,p,q;
scanf("%d%d%d",&op,&p,&q);
if (op==0)
{
if (p==o)
{
tot=tot-w[o]+q;
w[o]=q;
continue;
}
t=c[p];
if(e[t]) tot=tot-r[t]+q;
updata(st[t],q-r[t]);
updata(en[t]+1,r[t]-q);
r[t]=q;
}else
{
int lca=query(p,q);
if (e[lca])
{
int t1=a[p],t2=a[q];
LL ans=sum(st[p])-sum(st[t1]);
ans=ans+sum(st[q])-sum(st[t2]);
if (L[t1]>L[t2]) swap(t1,t2);
LL t3=sum(st[t2])-sum(st[t1]);
t3=min(t3,tot-t3);
printf("%I64d\n",ans+t3);
}
else printf("%I64d\n",sum(st[p])+sum(st[q])-sum(st[lca])*2);
}
}
}
}