1. 程式人生 > >2018 Multi-University Training Contest 7 1008 Traffic Network in Numazu【樹鏈剖分】

2018 Multi-University Training Contest 7 1008 Traffic Network in Numazu【樹鏈剖分】

題意:N個節點N條邊的連通圖,有刪改操作和線上查詢兩點間的最短路。

分析:相當於是一顆樹上多了一條邊,那麼找到一條這樣的邊(滿足刪除之後餘下整體為樹)把它刪掉。對於兩點間的查詢,由於有修改,就採用樹鏈剖分跑線段樹的方法來解決就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; }