题目大意
给出一棵基环树,有两种操作:1)修改一条边的边权,2)查询一个点到另一个点的最小距离。
解题思路
基环树其实可以形象的理解为一个长了好几棵树的环,那么,取两个点共有以下两种情况:
1. 两点在同一棵树上;
2. 两点在不同根的两棵树上;
对于在同一棵树上的两个点,问题就是简单的树链剖分;对于在不同树上的两个点,距离可以转化为“两结点到根节点的距离+环上两个根节点的距离”。
树上点的距离用树链剖分维护,环上的距离用一个树状数组维护。
代码
写死我了
#include <bits/stdc++.h>
using namespace std;
const int BUF=80000000;
char Buf[BUF], *buf=Buf;
inline void read(int& a) {for(a=0;*buf<48;buf++); while(*buf>47) a=a*10+*buf++-48;}
const int maxn=int(1e5)+111;
typedef long long ll;
int n,m;
struct Edge {
int from,to,next,cost;
Edge() {}
Edge(int f,int a,int b,int c):from(f),to(a),next(b),cost(c) {}
}eage[maxn*2];
int head[maxn], tot=0;
void init_eage() {
tot=0;
for(int i=1;i<=n;++i) head[i]=-1;
return;
}
void add_eage(int u,int v,int w) {
eage[tot]=Edge(u,v,head[u],w), head[u]=tot++;
eage[tot]=Edge(v,u,head[v],w), head[v]=tot++;
return;
}
int sta[maxn], tp=0;
int cir[maxn], cnt=0;
bool insta[maxn], incir[maxn];
void init_dfs() {
tp=cnt=0;
for(int i=1;i<=n;++i)
insta[i]=incir[i]=false;
return;
}
bool get_circle(int u,int fa) {
if(insta[u]) {
for(int i=tp;;--i) {
cir[++cnt]=sta[i], incir[sta[i]]=true;
if(sta[i]==u) break;
}
return true;
}
insta[u]=true, sta[++tp]=u;
for(int i=head[u];~i;i=eage[i].next) if(eage[i].to!=fa) {
bool flag=get_circle(eage[i].to,u);
if(flag) return true;
}
insta[u]=false, tp--;
return false;
}
int val[maxn];
void get_val(int u,int fa) {
for(int i=head[u];~i;i=eage[i].next) if(eage[i].to!=fa && !incir[eage[i].to]) {
val[eage[i].to]=eage[i].cost;
get_val(eage[i].to,u);
}
return;
}
int fa[maxn], dep[maxn], siz[maxn], son[maxn];
void dfs1(int u,int f,int d) {
fa[u]=f, siz[u]=1, dep[u]=d, son[u]=0;
for(int i=head[u];~i;i=eage[i].next) if(eage[i].to!=f && !incir[eage[i].to]) {
int v=eage[i].to;
dfs1(v,u,d+1);
siz[u]+=siz[v];
if(!son[u] || siz[v]>siz[son[u]])
son[u]=v;
}
return;
}
int bel[maxn], top[maxn], ind[maxn];
vector<int> seq[maxn];
void dfs2(int u,int rt) {
seq[rt].push_back(u);
ind[u]=(int)seq[rt].size()-1;
bel[u]=rt;
if(u==son[fa[u]]) top[u]=top[fa[u]];
else top[u]=u;
if(son[u]) dfs2(son[u],rt);
for(int v,i=head[u];~i;i=eage[i].next) if((v=eage[i].to)!=son[u] && v!=fa[u] && !incir[v])
dfs2(v,rt);
return;
}
void init_val() {
for(int i=1;i<=n;++i)
val[i]=0, seq[i].clear();
return;
}
#define mid ((l+r)>>1)
const int maxtot=maxn*20;
int root[maxn], ls[maxtot], rs[maxtot], pt;
ll sum[maxtot];
void node_init(int k) {
ls[k]=rs[k]=sum[k]=0;
return;
}
void build_(int k,int l,int r,int rt) {
if(l==r) {
sum[k]=val[seq[rt][l]];
return;
}
if(!ls[k]) ls[k]=++pt, node_init(pt);
if(!rs[k]) rs[k]=++pt, node_init(pt);
build_(ls[k],l,mid,rt), build_(rs[k],mid+1,r,rt);
sum[k]=sum[ls[k]]+sum[rs[k]];
return;
}
void tree_build() {
register int i;
pt=0;
for(i=1;i<=cnt;++i) {
get_val(cir[i],0);
dfs1(cir[i],0,1), dfs2(cir[i],cir[i]);
root[cir[i]]=++pt, node_init(pt);
build_(root[cir[i]],0,seq[cir[i]].size()-1,cir[i]);
}
return;
}
int POS;
ll VAL;
void modify(int k,int l,int r) {
if(l==r) {
sum[k]=VAL;
return;
}
if(POS<=mid) modify(ls[k],l,mid);
if(POS> mid) modify(rs[k],mid+1,r);
sum[k]=sum[ls[k]]+sum[rs[k]];
return;
}
void tree_modify(int pos,int val) {
POS=ind[pos], VAL=val;
modify(root[bel[pos]],0,seq[bel[pos]].size()-1);
return;
}
int L,R;
ll query_(int k,int l,int r) {
if(L<=l && r<=R) return sum[k];
ll res=0;
if(L<=mid) res+=query_(ls[k],l,mid);
if(R> mid) res+=query_(rs[k],mid+1,r);
return res;
}
ll query(int u,int v,int rt) {
L=ind[u], R=ind[v];
if(L>R) swap(L,R);
return query_(root[rt],0,(int)seq[rt].size()-1);
}
ll tree_query(int u,int v,int rt) {
if(u==v) return 0;
ll res=0;
while(top[u]!=top[v]) {
if(dep[top[u]]<dep[top[v]]) swap(u,v);
res+=query(u,top[u],rt);
u=fa[top[u]];
}
if(dep[u]>dep[v]) swap(u,v);
res-=query(u,u,rt);
res+=query(u,v,rt);
return res;
}
#define lowbit(k) ((k)&(-(k)))
ll vc[maxn], cir_sum=0;
int pos[maxn];
void cir_add(int pos,ll val) {
for(;pos<=n;pos+=lowbit(pos))
vc[pos]+=val;
return;
}
ll vc_query(int pos) {
ll res=0;
for(;pos>=1;pos-=lowbit(pos))
res+=vc[pos];
return res;
}
void get_cir_val(int u,int last,int p) {
if(p==cnt) return;
for(int i=head[u];~i;i=eage[i].next) if(eage[i].to==cir[p+1]) {
cir_add(p+1,eage[i].cost);
get_cir_val(eage[i].to,u,p+1);
}
return;
}
void init_cir() {
register int i;
cir_sum=0;
for(i=0;i<=n;++i)
pos[i]=vc[i]=0;
return;
}
void cir_build() {
register int i;
for(i=1;i<=cnt;++i)
pos[cir[i]]=i;
get_cir_val(cir[1],0,1);
for(i=0;i<tot;++i) if(incir[eage[i].from] && incir[eage[i].to])
cir_sum+=eage[i].cost;
cir_sum>>=1;
return;
}
ll cir_query(int u,int v) {
if(pos[u]>pos[v]) swap(u,v);
ll res1=vc_query(pos[v])-vc_query(pos[u]);
return min(res1,cir_sum-res1);
}
ll QUERY(int u,int v) {
if(bel[u]==bel[v])
return tree_query(u,v,bel[u]);
ll res=tree_query(u,bel[u],bel[u])+tree_query(v,bel[v],bel[v]);
res+=cir_query(bel[u],bel[v]);
return res;
}
void MODIFY(int id,ll val) {
id=(id-1)<<1;
int u=eage[id].from, v=eage[id].to;
if(incir[u] && incir[v]) {
if(pos[u]>pos[v]) swap(u,v);
cir_sum-=eage[id].cost;
if(pos[u]!=1 || pos[v]!=cnt) cir_add(pos[v],-eage[id].cost);
eage[id].cost=eage[id^1].cost=val;
cir_sum+=eage[id].cost;
if(pos[u]!=1 || pos[v]!=cnt) cir_add(pos[v],eage[id].cost);
} else {
if(dep[u]>dep[v]) swap(u,v);
eage[id].cost=eage[id^1].cost=val;
tree_modify(v,val);
}
return;
}
void init() {
init_cir();
init_val();
init_dfs();
init_eage();
return;
}
void work() {
read(n), read(m);
init();
register int i,u,v,w;
for(i=0;i<n;++i) {
read(u), read(v), read(w);
add_eage(u,v,w);
}
get_circle(1,0);
tree_build();
cir_build();
int op,x,y;
for(i=1;i<=m;++i) {
read(op), read(x), read(y);
if(op==0) MODIFY(x,y);
else printf("%I64d\n",QUERY(x,y));
}
return;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("input0.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
fread(Buf,1,BUF,stdin);
int T;
for(read(T);T;T--)
work();
return 0;
}