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();
}
}
标签:F2,mxx,dep,back,int,CF2013,ask,mx
From: https://www.cnblogs.com/spdarkle/p/18426119