http://acm.hdu.edu.cn/showproblem.php?pid=6393
题意
给n个点和n条边的图,有两种操作,一种修改边权,另一种查询u到v的最短路。
分析
n个点和n条边,实际上是一棵树+一个环,如果仅仅是一棵树,那么这题就是树链剖分的模板题了。
对于环来说,可以考虑先把环中一条边提取出来,然后树链剖分,修改时用线段树,单点修改和区间求和。
查询时就考虑三种情况,u走树上到v,从u经过提取出来的边再到v(两种),取最小值。
至于取出环上一条边,用并查集搞搞。
#include<bits/stdc++.h>#define mem(a,b) memset(a,b,sizeof(a))using namespace std;typedef long long ll;const int inf = 0x3f3f3f3f;const int maxn = 2e5+5;struct side { ???int u,v,w; ???int ne;} s[maxn];struct edge { ???int l,r; ???ll v;} e[maxn<<2];int n,q;int head[maxn],len;int val[maxn],hold[maxn],pre[maxn];int deep[maxn],fa[maxn],ve[maxn],son[maxn],top[maxn],p[maxn],fp[maxn],sz;void add(int u,int v,int w) { ???s[len].u = u; ???s[len].v = v; ???s[len].w = w; ???s[len].ne = head[u]; ???head[u] = len++;}int find(int x) { ???return pre[x] == x?x:pre[x] = find(pre[x]);}void dfs1(int u,int p,int d) { ???deep[u] = d; ???fa[u] = p; ???ve[u] = 1; ???son[u] = -1; ???for(int i = head[u]; i!= -1; i = s[i].ne) { ???????if(s[i].v == p) continue; ???????val[s[i].v] = s[i].w; //把边权值赋给相连的点 ???????hold[i>>1] = s[i].v;//这条边的权值被哪个点掌握着 ???????dfs1(s[i].v,u,d+1); ???????ve[u]+= ve[s[i].v]; ???????if(son[u] == -1||ve[s[i].v]> ve[son[u]]) ???????????son[u] = s[i].v; ???} ???return ;}void dfs2(int u,int sp) { ???top[u] = sp; ???p[u] = ++sz; ???fp[p[u]] = u; ???if(son[u] == -1) return ; ???dfs2(son[u],sp); ???for(int i = head[u]; i!= -1; i = s[i].ne) { ???????if(s[i].v == son[u]||s[i].v == fa[u]) continue; ???????dfs2(s[i].v,s[i].v); ???} ???return ;}void build(int i,int l,int r) { ???e[i].l = l; ???e[i].r = r; ???if(l == r) { ???????e[i].v = val[fp[l]]; ???????return ; ???} ???int mid = (l+r)>>1; ???build(i<<1,l,mid); ???build(i<<1|1,mid+1,r); ???e[i].v = e[i<<1].v+e[i<<1|1].v;}void modify(int i,int pos,int v) { ???if(pos> e[i].r||pos< e[i].l) return ; ???if(e[i].l == e[i].r) { ???????e[i].v = v; ???????return ; ???} ???modify(i<<1,pos,v); ???modify(i<<1|1,pos,v); ???e[i].v = e[i<<1].v+e[i<<1|1].v;}ll query(int i,int l,int r) { ???if(e[i].r< l||e[i].l> r) return 0; ???if(e[i].l>= l&&e[i].r<= r) return e[i].v; ???return query(i<<1,l,r)+query(i<<1|1,l,r);}ll demand(int x,int y) { ???int fx = top[x]; ???int fy = top[y]; ???ll ans = 0; ???while(fx!= fy) { ???????if(deep[fx]< deep[fy]) { ???????????swap(fx,fy); ???????????swap(x,y); ???????} ???????ans+= query(1,p[fx],p[x]); ???????x = fa[fx]; ???????fx = top[x]; ???} ???if(x == y) return ans; ???if(deep[x]> deep[y]) swap(x,y); ???ans+= query(1,p[son[x]],p[y]); ???return ans;}void init() { ???sz = len = 0; ???mem(head,-1); ???for(int i = 0; i<= n; i++) pre[i] = i;}int main() { ???int t; ???cin>>t; ???while(t--) { ???????int su,sv,sc,ss; ???????scanf("%d %d",&n,&q); ???????init(); ???????for(int i = 1; i<= n; i++) { ???????????int u,v,w; ???????????scanf("%d %d %d",&u,&v,&w); ???????????int fx = find(u); ???????????int fy = find(v); ???????????if(fx == fy) { ???????????????len+= 2; ???????????????ss = i; ???????????????su = u; ???????????????sv = v; ???????????????sc = w; ???????????????continue; ???????????} else ???????????????pre[fy] = fx; ???????????add(u,v,w); ???????????add(v,u,w); ???????} ???????dfs1(1,-1,1); ???????dfs2(1,1); ???????build(1,1,n); ???????while(q--) { ???????????int o,x,y; ???????????scanf("%d %d %d",&o,&x,&y); ???????????if(o == 0) { ???????????????x--; ???????????????if(x == ss) { ???????????????????sc = y; ???????????????????continue; ???????????????} ???????????????modify(1,p[hold[x]],y); ???????????} else { ???????????????ll ans; ???????????????ans = sc+min(demand(x,su)+demand(y,sv),demand(x,sv)+demand(y,su)); ???????????????ans = min(ans,demand(x,y)); ???????????????printf("%lld\n",ans); ???????????} ???????} ???} ???return 0;}
HDU - 6393 Traffic Network in Numazu(树链剖分+基环树)
原文地址:https://www.cnblogs.com/fht-litost/p/9557714.html