狭义的圆方树 洛谷P5236 圆方树模板题
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; const int N=3e5+10; struct node{ int nxt,w,to; }e[N],E[N]; int head[N],Head[N],cnt,Cnt; int fa[N],deep[N],top[N],son[N],siz[N],S[N],dis[N]; int n,m,q,An,Bn; int sum[N]; int dfn[N],low[N],tot; void add(int from,int to,int w){ e[++cnt].nxt=head[from]; e[cnt].w=w; e[cnt].to=to; head[from]=cnt; } void Add(int from,int to,int w){ E[++Cnt].nxt=Head[from]; E[Cnt].w=w; E[Cnt].to=to; Head[from]=Cnt; } void dfs1(int from,int Fa,int dep){ fa[from]=Fa; deep[from]=dep; siz[from]=1; son[from]=0; int maxson=0; for(int i=Head[from];i;i=E[i].nxt){ int to=E[i].to; if(to==Fa)continue; dis[to]=dis[from]+E[i].w; dfs1(to,from,dep+1); siz[from]+=siz[to]; if(maxson<siz[to]){ maxson=siz[to]; son[from]=to; } } } void dfs2(int from,int topf){ top[from]=topf; if(!son[from])return; dfs2(son[from],topf); for(int i=Head[from];i;i=E[i].nxt){ int to=E[i].to; if(to==son[from]||to==fa[from])continue; dfs2(to,to); } } int lca(int x,int y){ while(top[x]!=top[y]){ if(deep[top[x]]<deep[top[y]])swap(x,y); x=fa[top[x]]; } if(deep[x]>deep[y])swap(x,y); return x; } int find(int P,int x){ int res=x; while(top[x]!=top[P]){ res=top[x]; x=fa[top[x]]; } if(P==x)return res; else return son[P]; } void build(int from,int to,int w){ ++Bn; int now=to,res=w; while(now!=fa[from]){ sum[now]=res; res+=S[now]; now=fa[now]; } sum[Bn]=sum[from]; sum[from]=0; now=to; while(now!=fa[from]){ int Bw=min(sum[now],sum[Bn]-sum[now]); Add(now,Bn,Bw); Add(Bn,now,Bw); now=fa[now]; } return; } void tarjan(int from,int Fa){ dfn[from]=low[from]=++tot; for(int i=head[from];i;i=e[i].nxt){ int to=e[i].to; int w=e[i].w; if(to==Fa)continue; if(!dfn[to]){ fa[to]=from; S[to]=w; tarjan(to,from); low[from]=min(low[from],low[to]); }else{ low[from]=min(low[from],dfn[to]); } if(low[to]<=dfn[from])continue; Add(from,to,w); Add(to,from,w); } for(int i=head[from];i;i=e[i].nxt){ int to=e[i].to; int w=e[i].w; if(fa[to]==from||dfn[to]<dfn[from])continue; build(from,to,w); } return; } int main(){ scanf("%d%d%d",&An,&m,&q); for(int i=1;i<=m;i++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); add(x,y,z); add(y,x,z); } Bn=An; tarjan(1,0); dfs1(1,0,1); dfs2(1,1); for(int i=1;i<=q;i++){ int x,y; scanf("%d%d",&x,&y); int L=lca(x,y); if(L<=An){ int ans=dis[y]+dis[x]-2*dis[L]; printf("%d ",ans); }else{ int X=find(L,x); int Y=find(L,y); int ans=min(abs(sum[X]-sum[Y]),sum[L]-abs(sum[X]-sum[Y])); ans+=dis[x]-dis[X]+dis[y]-dis[Y]; printf("%d ",ans); } } }
广义的圆方树 洛谷P4630 广义圆方树模板题
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; const int N=500010; struct node{ int nxt,to; }e[N],E[N]; int head[N],Head[N]; int cnt,Cnt,tot,num; int dfn[N],low[N],stk[N],tp,sum[N],siz[N]; long long ans; int n,Bn,m; void add(int from,int to){ e[++cnt].nxt=head[from]; e[cnt].to=to; head[from]=cnt; } void Add(int from,int to){ E[++Cnt].nxt=Head[from]; E[Cnt].to=to; Head[from]=Cnt; } void tarjan(int from){ dfn[from]=low[from]=++tot; stk[++tp]=from; num++; for(int i=head[from];i;i=e[i].nxt){ int to=e[i].to; if(!dfn[to]){ tarjan(to); low[from]=min(low[from],low[to]); if(low[to]==dfn[from]){ sum[++Bn]=0; while(stk[tp+1]!=to){ Add(stk[tp],Bn); Add(Bn,stk[tp]); sum[Bn]++; tp--; } Add(from,Bn); Add(Bn,from); sum[Bn]++; } }else { low[from]=min(low[from],dfn[to]); } } } void dfs(int from,int F){ if(from<=n)siz[from]=1; for(int i=Head[from];i;i=E[i].nxt){ int to=E[i].to; if(to==F)continue; dfs(to,from); ans+=(long long)2*sum[from]*siz[from]*siz[to]; siz[from]+=siz[to]; } ans+=(long long)2*sum[from]*siz[from]*(num-siz[from]); } int main(){ scanf("%d%d",&n,&m); Bn=n; for(int i=1;i<=n;i++)sum[i]=-1; for(int i=1;i<=m;i++){ int x,y; scanf("%d%d",&x,&y); add(x,y); add(y,x); } for(int i=1;i<=n;i++){ if(!dfn[i]){ num=0; tarjan(i); tp--; dfs(i,0); } } printf("%lld ",ans); }