CF2013 F2

CF2013 F2

首先你需要知道 F1 的做法。

我将会给出一个 \(O(n\sqrt n)\) 的,求出整棵树任意节点答案的方法。

对于路径上的点 \(p_1\sim p_m\),终点 \(p_m\),起点 \(p_1\)

\(p_i\) 所经不在路径上的最远长度为 \(d_i\)

那么根据 F1 的结论,我们是通过移动两个指针 \(l,r\),不断判断是否有 \(d_l+l>\max_{k\in [l,r]}(m-k+1+d_k)\)\(d_r+m-r+1\ge \max_{k\in [l,r]}d_k+k\)

在这里我们设 \(a_i=d_i+i,b_i=d_i-i+1\),然后利用 ST 表维护最值进行判断。

事实上我们观察 \(i\) 其实是深度,与此同时如果 \(p_i\to p_{i+1}\) 不是在 \(p_i\) 的树内最长路上的话,\(a_i\) 就是 \(a\) 的一个后缀最大值。反过来 \(b\) 可以从 \(p_m\) 为根的视角来看。

所以我们尝试在 ST 表中维护最值出现的位置,然后维护指针 \(l=1,r=m\),每次看谁移动得更少,就用谁进行判断,如果合法直接 return,否则跳到后继位置(下一个最值位置,注意值相同的跳到最后面去),当然反过来是同理的。

由于我们每一次记录了最值,所以不会影响判断结果的完备性。

而同时我们发现 \(l,r\) 指针所跳都是前/后缀最大值,而这种最大值都是各个长链的链顶提供的,所以总共 \(O(\sqrt n)\) 个,所以我们暴力检验就是正确的。

同时我们可以用尾插ST表,维护递归结构。

#include<bits/stdc++.h>
using namespace std;
#define N 205050
int lg[N],n,m,dep[N],ans[N],mx[N],lst[N];
struct ST{
	int f[N][20],v[N],tag;//尾插ST表hh
	void ins(int x,int k){
		f[x][0]=x,v[x]=k;
		for(int j=1;(1<<j)<=x;++j){
			int lt=x-(1<<j-1);
			f[x][j]=v[f[x][j-1]]>v[f[lt][j-1]]+tag?f[x][j-1]:f[lt][j-1];//维护最前面的/最后面的最值,tag=0说明是取最前的,tag=-1说明是取最后面的
		}
	}
	int ask(int l,int r){
		int k=lg[r-l+1];l+=(1<<k)-1;
		return v[f[r][k]]>v[f[l][k]]+tag?f[r][k]:f[l][k];
	}
}A,B;
vector<int>e[N];
void dfs(int u,int fa){
	lst[u]=fa;dep[u]=dep[fa]+1;
	for(auto v:e[u]){
		if(v==fa)continue;
		dfs(v,u);
		mx[u]=max(mx[u],mx[v]+1);
	}
}
void adt(int dep,int val){
	A.ins(dep,val+dep);
	B.ins(dep,val-dep+1);
}
bool check(int dep){
	if(dep<=1)return 1;
	int mid=dep+1>>1;
	int l=A.ask(1,mid),r=B.ask(mid+1,dep);
	while(1){//长剖,复杂度最多根号!
		if(l-1<=dep-r){
			if(A.v[l]>B.v[B.ask(l+1,dep-l+1)]+dep)return 1;
			if(l>=mid)return 0;
			l=A.ask(l+1,mid);
		}
		else {
			if(B.v[r]+dep>=A.v[A.ask(dep-r+2,r-1)])return 0;
			if(r<=mid+1)return 1;
			r=B.ask(mid+1,r-1);
		}
	}
	return 0;
}
void dfs2(int u,int fa){
	int mxx=0,cmx=0;
	for(auto v:e[u])if(v!=fa){
		if(mx[v]+1>=mxx)cmx=mxx,mxx=mx[v]+1;
		else cmx=max(cmx,mx[v]+1);
	}
	adt(dep[u],mxx);
	ans[u]=check(dep[u]);
	for(auto v:e[u])if(v!=fa){
		adt(dep[u],mx[v]+1==mxx?cmx:mxx);
		dfs2(v,u);
	}
}
void sol(){
	cin>>n;
	for(int i=1,u,v;i<n;++i)cin>>u>>v,e[u].push_back(v),e[v].push_back(u);
	dfs(1,0);
	dfs2(1,0);
	int u,v;cin>>u>>v;
	vector<int>nl,nr;
	while(u!=v){
		if(dep[u]>dep[v])nl.push_back(u),u=lst[u];
		else nr.push_back(v),v=lst[v];
	}
	reverse(nr.begin(),nr.end());
	nl.push_back(u);
	for(auto x:nl)cout<<(ans[x]?"Alice\n":"Bob\n");
	for(auto x:nr)cout<<(ans[x]?"Alice\n":"Bob\n");
	for(int i=1;i<=n;++i)mx[i]=lst[i]=0,e[i].clear();
}
signed main(){
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	B.tag=-1;
	lg[0]=-1;for(int i=1;i<=200000;++i)lg[i]=lg[i>>1]+1;
	int T;cin>>T;
	while(T--){
		sol();
	}
}
posted @ 2024-09-22 23:42  spdarkle  阅读(12)  评论(0编辑  收藏  举报