P13921 [PO Final 2024] 回家 Trafikverket's Mistake / 重剖 + 线段树优化建图
题目传送门:P13921 [PO Final 2024] 回家 Trafikverket's Mistake。
设题目说的 \(W_i,H_i\) 为 \(l_i,r_i\)。
首先有一个最暴力的算法,若 \(l_i,r_i\) 的路径没有遮挡,直接跑,否则继续等待,我们发现这样非常类似拓扑排序,直接一开始对满足在 \(l_i,r_i\) 的路径上的 \(l_j\),连 \(j\) 到 \(i\) 的有向边,表示 \(j\) 要先跑,\(i\) 才能跑,直接拓扑排序即可。
但是这样做是 \(O(n^2)\) 的,需要考虑优化。
考虑对原树重剖,对每条重链都建一颗线段树,那么 \(l_i\) 到 \(r_i\) 的路径最多只会经过 \(O(\log n)\) 条重链,然后直接边跳重链边线段树优化建图即可。
这里我们可以将每个 \(l_i\) 出现在线段树的位置标记一下,然后拓扑排序时只需要存标记过的位置,注意建图时要小心连成自环而且 \(l_i\) 不能被连因为自己不会堵自己,具体的可以看代码。
#include<bits/stdc++.h>
#define int long long
#define double long double
using namespace std;
const int N=2e5+10;
inline int read(){
char c=getchar();
int f=1,ans=0;
while(c<48||c>57) f=(c==45?f=-1:1),c=getchar();
while(c>=48&&c<=57) ans=(ans<<1)+(ans<<3)+(c^48),c=getchar();
return ans*f;
}
int n,m,sz[N],son[N],top[N],bot[N],dep[N],fa[N],nw[N],dfn[N],cnt;
vector<int>g1[N],g2[N<<2];
void dfs1(int u,int fa){
sz[u]=1,dep[u]=dep[fa]+1,::fa[u]=fa;
for (auto v:g1[u]) if (v^fa){
dfs1(v,u);
sz[u]+=sz[v];
if (sz[son[u]]<sz[v]) son[u]=v;
}
}
void dfs2(int u,int t){
dfn[u]=++cnt,nw[cnt]=u,top[u]=t,bot[t]=u;
if (!son[u]) return ;
dfs2(son[u],t);
for (auto v:g1[u]) if (v!=fa[u]&&v!=son[u]) dfs2(v,v);
}
int root[N],ls[N<<2],rs[N<<2],tot,id[N],d[N<<2],vis[N<<2];
#define lc ls[k]
#define rc rs[k]
void build(int &k,int l,int r){
if (!k) k=++tot;
if (l==r){id[nw[l]]=k;return ;}
int mid=l+r>>1;
build(lc,l,mid),build(rc,mid+1,r);
g2[lc].push_back(k),g2[rc].push_back(k),d[k]+=2;
}
void change(int k,int l,int r,int l1,int r1,int x){
if (l1>r1) return ;
if (l1<=l&&r1>=r){if (k!=x) g2[k].push_back(x),d[x]++;return ;}
int mid=l+r>>1;
if (l1<=mid) change(lc,l,mid,l1,r1,x);
if (r1>mid) change(rc,mid+1,r,l1,r1,x);
}
inline void topsort(){
queue<int>q;
for (int i=1;i<=tot;i++) if (!d[i]) q.push(i);
vector<int>anss;
while(!q.empty()){
int u=q.front();q.pop();
if (vis[u]) anss.push_back(vis[u]);
for (auto v:g2[u]) if (--d[v]==0) q.push(v);
}
if ((int)anss.size()!=m) puts("No");
else{
puts("Yes");
for (auto i:anss) printf("%lld ",i);
}
}
int l[N],r[N],mp[N];
inline void solve(int u,int v){
if (u==v) return ;
int tmp=u;
while(top[u]^top[v]){
if (dep[top[u]]<dep[top[v]]) swap(u,v);
int l=dfn[top[u]],r=dfn[u];
if (l==dfn[tmp]) l++;
if (r==dfn[tmp]) r--;
change(root[top[u]],dfn[top[u]],dfn[bot[top[u]]],l,r,id[tmp]);
u=fa[top[u]];
}
if (dep[u]<dep[v]) swap(u,v);
int l=dfn[v],r=dfn[u];
if (l==dfn[tmp]) l++;
if (r==dfn[tmp]) r--;
change(root[top[u]],dfn[top[u]],dfn[bot[top[u]]],l,r,id[tmp]);
}
main(){
n=read(),m=read();
for (int i=1;i<n;i++){
int u=read(),v=read();
g1[u].push_back(v),g1[v].push_back(u);
}
dfs1(1,0),dfs2(1,1);
for (int i=1;i<=n;i++) if (!mp[top[i]]) build(root[top[i]],dfn[top[i]],dfn[bot[top[i]]]),mp[top[i]]=1;
for (int i=1;i<=m;i++) l[i]=read(),r[i]=read(),vis[id[l[i]]]=i,solve(l[i],r[i]);
topsort();
return 0;
}

浙公网安备 33010602011771号