2018 Multi-University Training Contest 7 1008 Traffic Network in Numazu【樹鏈剖分】
阿新 • • 發佈:2018-12-24
題意:個節點條邊的連通圖,有刪改操作和線上查詢兩點間的最短路。
分析:相當於是一顆樹上多了一條邊,那麼找到一條這樣的邊(滿足刪除之後餘下整體為樹)把它刪掉。對於兩點間的查詢,由於有修改,就採用樹鏈剖分跑線段樹的方法來解決就OK。最後在計算答案的時候需要額外考慮經過那條散邊的答案。
散邊可以通過dfs判環來找到。
注意:散邊的更新操作,差點忘記更新跪在這 = =。
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <string.h>
using namespace std;
#define LL long long
const LL N = 100010;
struct EDGE {
LL v,nex;
} edge[N<<1];
LL head[N],tot;
LL dep[N],p[N],fa[N],top[N],son[N],siz[N],vis[N];
LL cnt,c[N];
LL flg,q,uu;
void addedge(LL a,LL b) {
edge[tot].v=b;
edge[tot].nex=head[a];
head[a]=tot++;
}
void judge(LL u,LL pre){
vis[u]=1 ;
for(LL i=head[u];i!=-1;i=edge[i].nex){
LL to=edge[i].v;
if(to==pre) {continue;}
if(!vis[to]) judge(to,u);
else{
flg=i;uu=u;return;
}
}
}
void dfs(LL u) {
siz[u]=1,son[u]=0;
for(LL i=head[u]; ~i; i=edge[i].nex) {
if(i==flg||(i==(flg^1 ))) continue;
LL v=edge[i].v;
if(v!=fa[u]) {
fa[v]=u;
dep[v]=dep[u]+1;
dfs(v);
if(siz[v]>siz[son[u]])son[u]=v;
siz[u]+=siz[v];
}
}
}
void build(LL u,LL tp) {
p[u]=++cnt;
top[u]=tp;
if(son[u])build(son[u],tp);
for(LL i=head[u]; ~i; i=edge[i].nex) {
if(i==flg||(i==(flg^1))) continue;
LL v=edge[i].v;
if(v!=son[u]&&v!=fa[u])build(v,v);
}
}
//樹狀陣列
LL lowbit(LL x) {
return x&(-x);
}
LL getsum(LL x) {
LL res=0;
while(x)res+=c[x],x-=lowbit(x);
return res;
}
void add(LL x,LL v) {
while(x<N)c[x]+=v,x+=lowbit(x);
}
LL query(LL x,LL y) {
return getsum(y)-getsum(x-1);
}
LL find(LL a,LL b) {
LL f1=top[a],f2=top[b],tmp=0;
while(f1!=f2) {
if(dep[f1]<dep[f2])swap(f1,f2),swap(a,b);
tmp+=query(p[f1],p[a]);
a=fa[f1],f1=top[a];
}
if(a==b)return tmp;
if(dep[a]>dep[b])swap(a,b);
return tmp+query(p[son[a]],p[b]);
}
LL n,u,v,ww,m,op,d[N][3];
int main() {
LL T;
//freopen("f.txt","r",stdin);
scanf("%lld",&T);
while(T--){
scanf("%lld %lld",&n,&m);
for(LL i=1;i<=n;i++) vis[i]=0;
LL root=1;
fa[root]=dep[root]=cnt=tot=0;
memset(siz,0,sizeof(siz));
memset(head,-1,sizeof(head));
memset(c,0,sizeof(c));
for(LL i=1; i<=n; i++) {
scanf("%lld%lld%lld",&u,&v,&ww);
addedge(u,v);
addedge(v,u);
d[i][0]=u;
d[i][1]=v;
d[i][2]=ww;
}
judge(1,-1);
dfs(root);
build(root,root);
LL vv=edge[flg].v;
LL wwi;
for(LL i=1;i<=n;i++){
if(d[i][0]==uu&&d[i][1]==vv||d[i][1]==uu&&d[i][0]==vv){
wwi=i;break;
}
}
for(LL i=1; i<=n; i++) {
if(i==wwi) continue;
if(dep[d[i][0]]>dep[d[i][1]])swap(d[i][0],d[i][1]);
add(p[d[i][1]],d[i][2]);
}
LL a,b;
while(m--) {
scanf("%lld",&op);
LL a,b;
scanf("%lld%lld",&a,&b);
if(op==1){
//cout<<wwi<<endl;
ww=d[wwi][2];
LL ans=find(a,b);
ans=min(ans,find(a,uu)+find(b,vv)+ww);
ans=min(ans,find(a,vv)+find(b,uu)+ww);
printf("%lld\n",ans);
}
else {
if(a!=wwi)
{add(p[d[a][1]],-d[a][2]);
add(p[d[a][1]],b);}
d[a][2]=b;
}
}
}
return 0;
}