题解:
不错的树链剖分练习题。
又是毒瘤仙人掌,先把环缩起来,然后链剖维护重链上相邻的环的最小值。
对于轻边特殊处理,此时要对每个环再维护一个线段树。
时间复杂度 O ( n log 2 n ) O(n \log^2 n) O(nlog2n)。
#include <bits/stdc++.h>
using namespace std;
typedef pair <int,int> pii;
const int RLEN=1<<18|1;
inline char nc() {
static char ibuf[RLEN],*ib,*ob;
(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
char ch=nc(); int i=0,f=1;
while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
return i*f;
}
const int N=2e5+50, inf=2e9;
int n,m,k,scc,cnt;
int anc[N],vis[N],dep[N];
int id[N],bl[N],head[N],tail[N];
int fa[N],top[N],sze[N],son[N],st[N],ind;
struct edge {int x,y,w;} e[N];
map <int,int> Mp[N];
vector <int> gi[N];
struct ST {
int mn[N*4];
inline void inc(int k,int l,int r,int p,int v) {
if(l==r) {mn[k]=v; return;}
int mid=(l+r)>>1;
(p<=mid) ? inc(k<<1,l,mid,p,v) : inc(k<<1|1,mid+1,r,p,v);
mn[k]=min(mn[k<<1],mn[k<<1|1]);
}
inline int ask(int k,int l,int r,int L,int R) {
if(L<=l && r<=R) return mn[k];
int mid=(l+r)>>1;
if(R<=mid) return ask(k<<1,l,mid,L,R);
else if(L>mid) return ask(k<<1|1,mid+1,r,L,R);
else return min(ask(k<<1,l,mid,L,R),ask(k<<1|1,mid+1,r,L,R));
}
inline void inc(int pos,int v) {inc(1,1,n,pos,v);}
inline int ask(int l,int r) {return (l>r) ? inf : ask(1,1,n,l,r);}
} tree,chain,cir;
inline int ga(int x) {return (anc[x]==x) ? x : (anc[x]=ga(anc[x]));}
inline void add(int x,int y) {gi[x].push_back(y); gi[y].push_back(x);}
inline int lca(int x,int y) {
while(top[x]^top[y]) (dep[top[x]]>dep[top[y]]) ? (x=fa[top[x]]) : (y=fa[top[y]]);
return (dep[x]<dep[y]) ? x : y;
}
inline void dfs(int x,int f) {
sze[x]=1; fa[x]=f; dep[x]=dep[f]+1;
for(auto v:gi[x]) if(v^f) {
dfs(v,x); sze[x]+=sze[v];
if(sze[son[x]]<sze[v]) son[x]=v;
}
}
inline void Dfs(int x,int f) {
st[x]=++ind; top[x]=f;
if(son[x]) Dfs(son[x],f);
for(auto v:gi[x]) if(v^fa[x] && v^son[x]) Dfs(v,v);
}
inline void work(int x,int y) {
static int ql[N],qr[N]; ql[0]=qr[0]=0;
while(x^y) (dep[x]<dep[y]) ? (qr[++qr[0]]=y, y=fa[y]) : (ql[++ql[0]]=x, x=fa[x]); ql[++ql[0]]=x;
while(qr[0]) ql[++ql[0]]=qr[qr[0]--];
++scc; head[scc]=cnt+1; tail[scc]=cnt+ql[0];
for(int i=1;i<=ql[0];i++) id[ql[i]]=++cnt, bl[ql[i]]=scc;
}
inline int calc(int a,int b) {
if(a==b) return inf;
if(id[a]>id[b]) swap(a,b);
int mn1=cir.ask(id[a]+1,id[b]);
int mn2=cir.ask(id[b]+1,tail[bl[b]]);
mn2=min(mn2,cir.ask(head[bl[a]],id[a]));
return min(INF,mn1+mn2;
}
inline void change(int i,int w) {
if(bl[e[i].x]^bl[e[i].y]) {
int x=(fa[bl[e[i].x]]==bl[e[i].y]) ? bl[e[i].x] : bl[e[i].y];
tree.inc(st[x],w);
} else {
int x=e[i].x, y=e[i].y;
if(id[x]>id[y]) swap(x,y);
if(id[x]==id[y]-1) cir.inc(id[y],w);
else cir.inc(id[x],w);
if(fa[bl[x]] && son[bl[x]]) {
int r=Mp[bl[x]][son[bl[x]]];
int a=(bl[e[r].x]==bl[x]) ? e[r].x : e[r].y;
r=Mp[bl[x]][fa[bl[x]]];
int b=(bl[e[r].x]==bl[x]) ? e[r].x : e[r].y;
chain.inc(st[bl[x]],calc(a,b));
}
}
}
inline void pre_calc() {
for(int i=1;i<=scc;i++)
if(fa[i] && son[i]) {
if(head[i]==tail[i]) chain.inc(st[i],inf);
} else chain.inc(st[i],inf);
for(int i=1;i<=m;i++) change(i,e[i].w);
}
inline int ask_tree(int x,int f) {
int ans=inf;
while(top[x]^top[f]) ans=min(ans,tree.ask(st[top[x]],st[x])), x=fa[top[x]];
if(x^f) ans=min(ans,tree.ask(st[son[f]],st[x]));
return ans;
}
inline pii ask_cir(int last,int f) {
int ans=inf;
while(top[bl[last]]^top[f]) {
int r=Mp[bl[last]][fa[bl[last]]];
int a=(bl[e[r].x]==bl[last]) ? e[r].x : e[r].y;
ans=min(ans,calc(last,a));
ans=min(ans,chain.ask(st[top[bl[last]]],st[bl[last]]-1));
r=Mp[top[bl[last]]][fa[top[bl[last]]]];
last=(bl[e[r].x]==top[bl[last]]) ? e[r].y : e[r].x;
}
if(bl[last]^f) {
int r=Mp[bl[last]][fa[bl[last]]];
int a=(bl[e[r].x]==bl[last]) ? e[r].x : e[r].y;
ans=min(ans,calc(last,a));
ans=min(ans,chain.ask(st[f]+1,st[bl[last]]-1));
r=Mp[son[f]][f];
last=(bl[e[r].x]==f) ? e[r].x : e[r].y;
} return pii(ans,last);
}
int main() {
n=rd(), m=rd();
for(int i=1;i<=n;i++) anc[i]=i;
for(int i=1;i<=m;i++) e[i].x=rd(), e[i].y=rd(), e[i].w=rd();
for(int i=1;i<=m;i++) if(ga(e[i].x)^ga(e[i].y)) {
anc[ga(e[i].x)]=ga(e[i].y); vis[i]=1;
add(e[i].x,e[i].y);
} dfs(1,0);
for(int i=1;i<=m;i++) if(!vis[i]) work(e[i].x,e[i].y);
for(int i=1;i<=n;i++) if(!bl[i]) bl[i]=++scc, id[i]=++cnt;
for(int i=1;i<=n;i++) gi[i].clear();
for(int i=1;i<=m;i++) if(bl[e[i].x]^bl[e[i].y]) {
Mp[bl[e[i].x]][bl[e[i].y]]=Mp[bl[e[i].y]][bl[e[i].x]]=i;
add(bl[e[i].x],bl[e[i].y]);
}
memset(sze,0,sizeof(sze)); memset(son,0,sizeof(son));
dfs(1,0); Dfs(1,1);
pre_calc(); k=rd();
for(int i=1;i<=k;i++) {
int op=rd(), x=rd(), y=rd();
if(op==1) change(x,y);
else {
int l=lca(bl[x],bl[y]), ans=inf;
ans=min(ans,min(ask_tree(bl[x],l),ask_tree(bl[y],l)));
pii tx=ask_cir(x,l), ty=ask_cir(y,l);
ans=min(ans,min(tx.first,ty.first));
ans=min(ans,calc(tx.second,ty.second));
printf("%d\n",ans);
}
}
}