題目鏈接
題意:
給定一個 個點 條邊的圖,每條邊都權值,有 次操作,一種操作修改一條邊的值,另一種操作查詢 到 的最短路
思路:
如果是一顆樹那麼這個問題可以被樹剖加線段樹輕鬆的解決,已知這張圖實際上是一棵樹加上一條邊構成,那麼可以將其刪掉一條邊 變成一顆樹進行處理。那麼現在查詢 的最短路,可以分成三種情況,一種直接從樹上走 ,一種經過 即,另一種反過來 ,取一個最小值即可。
代碼:
#include <bits/stdc++.h>
#define ll long long
#define ls x<<1
#define rs x<<1|1
using namespace std;
const int N=3e5+10;
int TT,n,q,op,x,y,U,V,W;
int bq[N],dq[N],dy[N];//邊權和點權,將邊權放到深度更大的點上,保存對應關係
//樹鏈剖分
struct edge{
int to,next,id,w;
}e[N*2];
int cnt,head[N];
void add(int u,int v,int w,int id){
e[++cnt].to=v;e[cnt].next=head[u];e[cnt].id=id;e[cnt].w=w;head[u]=cnt++;
}
int tot[N],son[N],deep[N],fa[N];
int dfs1(int u,int f,int dep){
tot[u]=1;fa[u]=f;deep[u]=dep;
int pd=-1;
for(int i=head[u];~i;i=e[i].next){
int v=e[i].to;
if(v==f)continue;
dq[v]=bq[e[i].id];dy[e[i].id]=v;
tot[u]+=dfs1(v,u,dep+1);
if(tot[v]>pd)pd=tot[v],son[u]=v;
}
return tot[u];
}
int idx[N],top[N],id[N],cnt1;
void dfs2(int u,int f){
idx[u]=++cnt1,id[cnt1]=u;
top[u]=f;
if(!son[u])return ;
dfs2(son[u],f);
for(int i=head[u];~i;i=e[i].next){
int v=e[i].to;
if(!idx[v])dfs2(v,v);
}
}
int lca(int x,int y){
while(top[x]!=top[y]){
if(deep[top[x]]<deep[top[y]])swap(x,y);
x=fa[top[x]];
}
if(deep[x]>deep[y])swap(x,y);
return x;
}
//線段樹
struct node{
int l,r;
ll sum;
}T[N*4];
void up(int x){
T[x].sum=T[ls].sum+T[rs].sum;
}
void built(int x,int l,int r){
T[x].l=l;T[x].r=r;
if(l==r){
T[x].sum=dq[id[l]];return ;
}
int mid=(l+r)/2;
built(ls,l,mid);built(rs,mid+1,r);
up(x);
}
void add(int x,int pos,ll val){
if(T[x].l==T[x].r){
T[x].sum=val;return ;
}
int mid=(T[x].l+T[x].r)/2;
if(pos<=mid)add(ls,pos,val);
else add(rs,pos,val);
up(x);
}
ll query(int x,int LL,int RR){
if(T[x].l>=LL&&T[x].r<=RR){
return T[x].sum;
}
int mid=(T[x].l+T[x].r)/2;
ll ans=0;
if(LL<=mid)ans+=query(ls,LL,RR);
if(RR>mid)ans+=query(rs,LL,RR);
return ans;
}
ll ljsum(int x,int y){
ll ans=0;
while(top[x]!=top[y]){
if(deep[top[x]]<deep[top[y]])swap(x,y);
ans+=query(1,idx[top[x]],idx[x]);
x=fa[top[x]];
}
if(deep[x]>deep[y])swap(x,y);
ans+=query(1,idx[x],idx[y]);
//cout<<x<<endl;
ans-=dq[x];//lca的邊權被計算,應該減去
return ans;
}
void init(int n){
memset(head,-1,sizeof(head));cnt=cnt1=0;
for(int i=1;i<=n;i++)idx[i]=id[i]=top[i]=fa[i]=deep[i]=son[i]=tot[i]=dy[i]=dq[i]=0;
}
int main()
{
scanf("%d",&TT);
while(TT--){
scanf("%d%d",&n,&q);init(n);
for(int i=1,u,v,w;i<n;i++){
scanf("%d%d%d",&u,&v,&w);
add(u,v,w,i);add(v,u,w,i);bq[i]=w;
}
dfs1(1,0,1);dfs2(1,0);built(1,1,n);
scanf("%d%d%d",&U,&V,&W);//刪去一條邊
while(q--){
scanf("%d%d%d",&op,&x,&y);
if(op==0){
if(x!=n)add(1,idx[dy[x]],y),dq[dy[x]]=y;
else W=y;
}else{
ll ans1=ljsum(x,y);//3種情況討論
ll ans2=ljsum(x,U)+W+ljsum(V,y);
ll ans3=ljsum(x,V)+W+ljsum(U,y);
printf("%lld\n",min(ans1,min(ans2,ans3)));
}
}
}
}