HDU 6392 Traffic Network in Numazu,
题目连接: Traffic Network in Numazu,
题意:给你一颗基环树,让你支持两种操作,第一种询问从x到y的最短路径和,第二种修改某一条边的边权。
题解:如果只是树上的话,就是裸的树链抛分。现在多了一条边,有环就不好做了,我们可以去掉环上的一条边然后就是一棵树了,然后怎么去边就是用并查集维护就可以了,每次来一条边就连接这个两个并查集,如果这两个并查集已经在一起了就说明这条边在环上。
#include<bits/stdc++.h> #define ll long long #define ls l,m,rt<<1 #define rs m+1,r,rt<<1|1 #define eps 1e-10; using namespace std; const int N = 1e5+7; int n,m; int head[N],cnt,to[N*2],nxt[N*2],w[N*2],id[N*2],te;//存边 struct edge { int u,v,w; }e[N]; bool vis[N]; void add_edge(int u,int v,int len,int idx) { to[++cnt]=v;w[cnt]=len;id[cnt]=idx;nxt[cnt]=head[u];head[u]=cnt; } //并查级找环上的边 int pre[N]; int find(int x) { return pre[x]==x?x:pre[x]=find(pre[x]); } int dep[N],fa[N],top[N],tid[N],son[N],siz[N],cn,num[N]; //树链抛分部分 void dfs1(int u,int f,int d,int len)//第一次dfs用来找重儿子,深度,子树大小,父亲,以及把边权付给更深的那一点 { fa[u]=f;dep[u]=d;siz[u]=1;num[u]=len; for(int i=head[u];i;i=nxt[i]) { if(id[i]==te)continue; if(to[i]!=f) { dfs1(to[i],u,d+1,w[i]);siz[u]+=siz[to[i]]; if(son[u]==-1||siz[to[i]]>siz[son[u]])son[u]=to[i]; } } } void dfs2(int v,int tp)//得到重链的头节点,以及时间戳 { top[v]=tp; tid[v]=++cn; if(son[v]==-1)return; dfs2(son[v],tp); for(int i=head[v];i;i=nxt[i]) { if(id[i]==te)continue; if(to[i]!=fa[v]&&to[i]!=son[v]) { dfs2(to[i],to[i]); } } } //线段树部分 ll sum[N<<2],val[N];//线段树维护和 void push_up(int rt) { sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } void built(int l,int r,int rt)//建树 { if(l==r) { sum[rt]=val[l]; return ; } int m=(l+r)>>1; built(ls); built(rs); push_up(rt); } void update(int p,int va,int l,int r,int rt)//单点更新 { if(l==r) { sum[rt]=va;return; } int m=(l+r)>>1; if(p<=m)update(p,va,ls); else update(p,va,rs); push_up(rt); } ll query(int L,int R,int l,int r,int rt)//询问和 { if(L<=l&&r<=R) { return sum[rt]; } int m=l+r>>1;ll ans=0; if(L<=m)ans+=query(L,R,ls); if(R>m)ans+=query(L,R,rs); return ans; } ll slove(int x,int y)//求x到y的最短距离 { ll ans=0; int fx=top[x],fy=top[y]; while(top[fx]!=top[fy]) { if(dep[fx]>dep[fy]) { ans+=query(tid[fx],tid[x],1,n,1);x=fa[fx]; } else { ans+=query(tid[fy],tid[y],1,n,1);y=fa[fy]; } fx=top[x];fy=top[y]; } if(x!=y) { if(dep[x]>dep[y])swap(x,y); ans+=query(tid[son[x]],tid[y],1,n,1);//注意细节不要加lca的权值 } return ans; } void init() { cn=cnt=0;te=0; memset(head,0,sizeof(head)); memset(son,-1,sizeof(son)); for(int i=0;i<=n;i++)pre[i]=i; } int main(){ int T; scanf("%d",&T); while(T--) { scanf("%d %d",&n,&m); init(); for(int i=1;i<=n;i++) { int u,v,w; scanf("%d %d %d",&u,&v,&w); e[i].u=u;e[i].v=v;e[i].w=w; if(te==0) { int fu=find(u),fv=find(v); if(fu==fv) { te=i; } else pre[fu]=fv; } add_edge(u,v,w,i); add_edge(v,u,w,i); } dfs1(1,0,0,0); dfs2(1,1); num[1]=0; for(int i=1;i<=n;i++)val[tid[i]]=num[i]; built(1,n,1); while(m--) { int op,x,y; scanf("%d %d %d",&op,&x,&y); if(op) { ll ans=slove(x,y); ans=min(ans,e[te].w+slove(x,e[te].u)+slove(y,e[te].v)); ans=min(ans,e[te].w+slove(y,e[te].u)+slove(x,e[te].v)); printf("%lld ",ans); } else { if(x==te)e[x].w=y; else { if(dep[e[x].u]>dep[e[x].v])update(tid[e[x].u],y,1,n,1); else update(tid[e[x].v],y,1,n,1); } } } } return 0; }