题解:CF1712F Triameter
Eddie08012026 · · 题解
分析
加入了叶子之间长度为
这使得树的直径变成
其中
那么就会衍生出两种思考方式:
考虑固定 u ,考虑 v
由于
二分答案
对于
那么如何找到
这样就可以预处理出对于所有
时间复杂度
实则
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int p[N],n,st[N][25],dfn[N],fa[N],f[N],dep[N],cnt;
vector<int>z[N];
int get(int x,int y){
return dfn[x]<dfn[y]?x:y;
}
void dfs(int x){
dep[x]=dep[fa[x]]+1;
dfn[x]=++cnt;
st[cnt][0]=fa[x];
for(int i:z[x]){
if(i==fa[x])continue;
dfs(i);
}
}
void init(){
for(int i=1;i<=__lg(n);i++)for(int j=1;j+(1<<i)-1<=n;j++)st[j][i]=get(st[j][i-1],st[j+(1<<(i-1))][i-1]);
}
int lca(int x,int y){
if(x==y)return x;
int a=dfn[x],b=dfn[y];
if(a>b)swap(a,b);
int k=__lg(b-a);
a++;
return get(st[a][k],st[b-(1<<k)+1][k]);
}
int dist(int x,int y){
return dep[x]+dep[y]-2*dep[lca(x,y)];
}
int l,r,nowd,L[N],R[N];
vector<int>mo[N];
int main(){
// freopen("diameter.in","r",stdin);
// freopen("diameter.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=2;i<=n;i++){
cin>>fa[i];
z[i].push_back(fa[i]),z[fa[i]].push_back(i);
}
queue<int>ye;
for(int i=1;i<=n;i++){
if(z[i].size()==1)p[i]=-1,ye.push(i);
}
while(!ye.empty()){
int a=ye.front();
ye.pop();
for(int i:z[a]){
if(!f[i]&&!p[i]){
f[i]=f[a]+1;
ye.push(i);
}
}
}
for(int i=1;i<=n;i++)mo[f[i]].push_back(i);
dfs(1);
init();
for(int k=n;k>=0;k--){
for(int i:mo[k]){
if(!l&&!r)l=r=i,nowd=0;
else {
int a=dist(l,i),b=dist(r,i);
if(max(a,b)>nowd){
if(a>b)r=i,nowd=a;
else l=i,nowd=b;
}
}
}
L[k]=l,R[k]=r;
}
int q;
cin>>q;
while(q--){
int a;
cin>>a;
int ans=0;
for(int i=1;i<=n;i++){
while(ans<n){
int D=ans+1,k=max(D-a-f[i],0);
if(max(dist(L[k],i),dist(R[k],i))<D||!L[k])break;
ans=D;
}
}
cout<<ans<<" ";
}
return 0;
}
考虑固定 lca ,考虑 u,v
固定了
根据上面的方法处理
令
转移容易:
检查
-
在树上
dp 的过程中检查g_{u,k}+g_{v,D-k}+x 是否>D 。 -
检查
f_u+g_{u,D+1}+x 是否>D 。
问题在于当前
时间复杂度
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int n,p[N],fa[N],f[N],dep[N],son[N],*g[N],dp[N],*s=dp,h[N];
vector<int>z[N];
void dfs(int x){
h[x]=0;
dep[x]=dep[fa[x]]+1;
for(int i:z[x]){
if(i==fa[x])continue;
dfs(i);
h[x]=max(h[x],h[i]+1);
if(h[i]>=h[son[x]])son[x]=i;
}
}
//int wei=0;
void build(int x,int tp){
if(x==tp){
g[x]=s;
s+=h[x]+1;
// wei+=h[x]+1;
}
if(son[x])g[son[x]]=g[x]+1,build(son[x],tp);
for(int i:z[x])if(i!=fa[x]&&i!=son[x])build(i,i);
}
int a,ans;
void solve(int x){
for(int i:z[x]){
if(i!=fa[x])solve(i);
}
g[x][0]=f[x];
if(h[x])g[x][0]=max(g[x][0],g[x][1]);
for(int i:z[x]){
if(i==fa[x]||i==son[x])continue;
for(int d=0;d<=h[i];d++){
while(ans<n){
int k=max(0,ans-d);
if(k<=h[x]&&g[x][k]+g[i][d]+a>ans)ans++;
else break;
}
}
for(int d=h[i];d>=0;d--){
g[x][d+1]=max(g[x][d+1],g[i][d]);
}
if(h[x])g[x][0]=max(g[x][0],g[x][1]);
}
while(ans<h[x]&&f[x]+g[x][ans+1]+a>ans)ans++;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=2;i<=n;i++){
cin>>fa[i];
z[fa[i]].push_back(i);
}
for(int i=1;i<=n;i++){
f[i]=n+1;
if(z[i].size()==(i==1))p[i]=-1;
}
for(int i=n;i>=1;i--){
if(p[i]==-1)f[i]=0;
f[fa[i]]=min(f[fa[i]],f[i]+1);
}
dfs(1);
build(1,1);
int q;
cin>>q;
while(q--){
cin>>a;
ans=0;
solve(1);
cout<<ans<<' ';
}
return 0;
}