【HDU 6393】暑期多校day7 Traffic Network in Numazu (基環樹、樹鏈剖分)
阿新 • • 發佈:2018-12-11
題目大意
給出一棵基環樹,有兩種操作: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 #endif fread(Buf,1,BUF,stdin); int T; for(read(T);T;T--) work(); return 0; }
若您覺得此篇部落格寫得不錯,請別忘了點贊並關注我哦 >_<