1 条题解
-
0
自动搬运
来自洛谷,原作者为

Rainbow_qwq
**搬运于
2025-08-24 23:17:34,当前版本为作者最后更新于2025-06-05 10:57:25,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
这题的图是 Halin Graph,树宽为 ,可以构造 Halin Graph 树分解(code1),然后用逛公园一题树分解的做法解决(code2),复杂度 。
下面讲一点更 oi 的做法。
画图会发现这是一张平面图,由最外面的一个环(连起了所有叶子)和中间的一棵树组成。
对于这题,可以对树三度化,进行边分治。
对于树上被切开的两个连通块,两部分之间最多有三条边相连(环上两条边,一条树边)。
对于 个这几条边上的点,作为起点跑一遍最短路,然后把当前的询问答案都 chkmin 一下。
跨越两边的询问不必再递归,在同一边的询问递归下去,每个询问最多被递归 次。
复杂度 。
#include<bits/stdc++.h> #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) #define int long long using namespace std; #define fi first #define se second #define pb push_back #define mkp make_pair typedef pair<int,int>pii; typedef vector<int>vi; #define maxn 400005 #define inf 0x3f3f3f3f3f3f3f3f int n,nn,m,res[maxn]; int qu[maxn],qv[maxn]; int fa[maxn]; vector<pii>G[maxn]; struct edge{ int to,nxt,w; }e[maxn<<1]; int tot=1,head[maxn]; void adde(int u,int v,int w){ e[++tot]=(edge){v,head[u],w}; head[u]=tot; } void add(int u,int v,int w){ adde(u,v,w); adde(v,u,w); } void rebuild(int u,int pa){ int lst=u; for(auto it:G[u]){ int v=it.fi,w=it.se; if(v==pa)continue; rebuild(v,u); add(lst,++nn,0),add(nn,v,w); lst=nn; } } vector<pii>go[maxn]; #define iter(i,u,v,w) for(int i=head[u],v=e[i].to,w=e[i].w;i;i=e[i].nxt,v=e[i].to,w=e[i].w) int allsz,mn,id,sz[maxn]; bool vis[maxn<<1]; void gete(int u,int pa){ sz[u]=1; iter(i,u,v,w){ if(v==pa || vis[i])continue; gete(v,u); sz[u]+=sz[v]; if(mn>max(sz[v],allsz-sz[v])) mn=max(sz[v],allsz-sz[v]),id=i; } } int col[maxn]; int st[maxn],top; namespace D{ struct edge{ int to,nxt,w; }e[maxn<<1]; int tot,head[maxn]; void adde(int u,int v,int w){ e[++tot]=(edge){v,head[u],w}; head[u]=tot; } bool vis[maxn]; void dij(int u,int*dis){ For(i,1,top) vis[st[i]]=0,dis[st[i]]=inf; dis[u]=0; priority_queue<pii,vector<pii>,greater<pii>>q; q.push(mkp(0,u)); while(q.size()){ int u=q.top().se;q.pop(); if(vis[u])continue; vis[u]=1; iter(i,u,v,w){ if(dis[v]>dis[u]+w){ dis[v]=dis[u]+w; q.push(mkp(dis[v],v)); } } } } } void color(int u,int pa,int c){ col[u]=c; st[++top]=u; iter(i,u,v,w)if(!vis[i]&&v!=pa)color(v,u,c); } pii tmp[999]; int len,tw[999]; int dis[9][maxn]; void clear(){ For(i,1,top){ int u=st[i]; col[u]=0; D::head[u]=0; }top=0; D::tot=0; len=0; } void solve(int u,vi qs){ if(allsz==1||!qs.size())return; mn=inf,gete(u,0); int x=e[id].to,y=e[id^1].to; vis[id]=vis[id^1]=1; vi qx,qy; color(x,0,1); color(y,0,2); For(i,1,top){ int u=st[i]; iter(i,u,v,w){ if(!col[v])continue; D::adde(u,v,w); if(col[u]==1&&col[v]==2) tmp[++len]=mkp(u,v),tw[len]=w,assert(len<=3); } for(auto it:go[u]){ int v=it.fi,w=it.se; if(!col[v])continue; D::adde(u,v,w); if(col[u]==1&&col[v]==2) tmp[++len]=mkp(u,v),tw[len]=w,assert(len<=3); } } assert(len<=3); For(i,1,len){ D::dij(tmp[i].fi,dis[i*2-1]); D::dij(tmp[i].se,dis[i*2]); } for(auto it:qs){ int u=qu[it],v=qv[it]; if(col[u]>col[v])swap(u,v); if(col[u]!=col[v]){ For(i,1,len){ res[it]=min(res[it],dis[i*2-1][u]+dis[i*2][v]+tw[i]); } }else{ if(col[u]==1){ For(i,1,len) res[it]=min(res[it],dis[i*2-1][u]+dis[i*2-1][v]); qx.pb(it); }else{ For(i,1,len) res[it]=min(res[it],dis[i*2][u]+dis[i*2][v]); qy.pb(it); } } } clear(); allsz=sz[x],solve(x,qx); allsz=sz[y],solve(y,qy); } int leaf[maxn],lcnt; signed main() { n=read();nn=n; For(i,2,n){ fa[i]=read(); int w=read(); G[i].pb(mkp(fa[i],w)); G[fa[i]].pb(mkp(i,w)); } For(i,1,n) if(G[i].size()==1) leaf[lcnt++]=i; For(i,0,lcnt-1){ int u=leaf[i],v=leaf[(i+1)%lcnt]; int w=read(); go[u].pb(mkp(v,w)),go[v].pb(mkp(u,w)); } rebuild(1,0); allsz=nn; vi orz; m=read(); For(i,1,m){ qu[i]=read(),qv[i]=read(); orz.pb(i); res[i]=inf; } solve(1,orz); For(i,1,m){ printf("%lld\n",res[i]); } return 0; }
- 1
信息
- ID
- 12446
- 时间
- 6000ms
- 内存
- 1024MiB
- 难度
- 7
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者