题解:P12703 [KOI 2022 Round 2] 外环路
Rainbow_qwq · · 题解
这题的图是 Halin Graph,树宽为
下面讲一点更 oi 的做法。
画图会发现这是一张平面图,由最外面的一个环(连起了所有叶子)和中间的一棵树组成。
对于这题,可以对树三度化,进行边分治。
对于树上被切开的两个连通块,两部分之间最多有三条边相连(环上两条边,一条树边)。
对于
跨越两边的询问不必再递归,在同一边的询问递归下去,每个询问最多被递归
复杂度
#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;
}