专栏文章

题解:P11162 [BalkanOI 2023] Car Race

P11162题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@minsjkuf
此快照首次捕获于
2025/12/02 07:39
3 个月前
此快照最后确认于
2025/12/02 07:39
3 个月前
查看原文
首先只有相同深度的赛车可能相遇。考虑 dfs 一遍,然后在这个过程中记录每个点上一个与它深度相同的点以及它们的 LCA。LCA 可以用 tarjan 做到 O(nα(n))O(n\alpha(n)),也可以做到线性。
然后考虑按发生时间先后处理碰撞,相同深度的 22i,ji,j 的 LCA 的深度就是区间 min,所以可以每层一个链表维护还存在的节点,然后用优先队列维护目前最早的相遇即可,O(nlogn)O(n\log n)。可以把优先队列换成桶,O(n)O(n)
CPP
#include <bits/stdc++.h>
using namespace std;
int n,f[1000005],a[1000005],fd[1000005],dep[1000005],last[1000005],lst[1000005],nxt[1000005],pre[1000005];
vector<int> g[1000005],tag[1000005];
int find(int x){
	return fd[x]?fd[x]=find(fd[x]):x;
}
void dfs(int x){
	lst[x]=last[dep[x]],last[dep[x]]=x,nxt[x]=n+1;
	if(lst[x]){
		if(!a[lst[x]]) lst[x]=lst[lst[x]];
		nxt[lst[x]]=x;
		if(lst[x]){
			pre[x]=dep[find(lst[x])];
			if(a[x]) tag[pre[x]].push_back(x);
		}
	}
	for(int v:g[x])
		dfs(v);
	fd[x]=f[x];
}
int main(){
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n,nxt[n+1]=n+1;
	for(int i=2;i<=n;i++)
		cin>>f[i],f[i]++,dep[i]=dep[f[i]]+1,g[f[i]].push_back(i);
	for(int i=1;i<=n;i++) cin>>a[i];
	dfs(1);
	for(int i=1;i<=n;i++)
		if(!a[nxt[i]])
			nxt[i]=n+1;
	int mx=n;
	while(1){
		while(mx&&!tag[mx].size()) mx--;
		if(!mx) break;
		int u=tag[mx].back();
		tag[mx].pop_back();
		if(pre[u]<mx) continue;
		int l=lst[u],r=u;
		a[u]=a[l]=pre[u]=0;
		while(r<=n&&pre[nxt[r]]==mx) r=nxt[r],pre[r]=0,a[r]=0;
		while(l&&pre[l]==mx) pre[l]=0,l=lst[l],a[l]=0;
		pre[nxt[r]]=min(pre[nxt[r]],pre[l]),pre[l]=0,tag[pre[nxt[r]]].push_back(nxt[r]);
		lst[nxt[r]]=lst[l],nxt[lst[l]]=nxt[r];
	}
	for(int i=1;i<=n;i++)
		cout<<(a[i]?dep[i]:-1)<<' ';
	cout<<'\n';
	return 0;
}
/*
10
0 0 2 2 4 4 6 3 6 
0 0 1 0 0 1 1 1 1 1 
*/

评论

0 条评论,欢迎与作者交流。

正在加载评论...