悬关:为什么这个做法假了
查看原帖
悬关:为什么这个做法假了
525375
Richard_Whr楼主2023/10/23 16:51
/*
k=2:
预处理出st[],存储每个节点是否在路径上
对于每个直径上结点,预处理出:
    - 子树最长链长度
    - 子树内直径长度
记录k=1时的ans=(n-1)*2-len_d+1
对于第二条边,有三种连接方式,分别对应:
- 子树内非直径点连非直径点:ans-d+1
- 字数内非直径点连子树外非直径点:ans-(最长链1+最长链2)+1+2*两颗子树间距离
- 字数内非直径点连子树外非直径点:ans-最长链+1
*/
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N=2e5+10,M=N*2;
int h[N],e[M],ne[M],idx;
int dist[N];
int dis[N];
int dmax[N];
int maxl[N];
int n,k,L,R,D;
bool st[N];
int q[N];
int path[N],top;
int res;
int hh,tt;

void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

PII bfs(int S,int b){
    
    for(int i=0;i<=tt;i++) dist[q[i]]=0x3f3f3f3f;
    hh=0,tt=-1;
    q[++tt]=S,dist[S]=0;
    int res=S;
    while(hh<=tt)
    {
        int t=q[hh++];
        if(dist[t]>dist[res]) res=t;
        for(int i=h[t];~i;i=ne[i])
        {
            int j=e[i];
            if(st[j]&&j!=b) continue;
            if(dist[j]>dist[t]+1) 
            {
                dist[j]=dist[t]+1;
                q[++tt]=j;
            }
        }
    }
    
    return {res,dist[res]};
}

bool dfs(int u){
    st[u]=true;
    path[++top]=u;
    if(u==R) return true;
    for(int i=h[u];~i;i=ne[i])
    {
        int j=e[i];
        if(st[j]) continue;
        if(dfs(j)) return true;
    }
    st[u]=false;
    top--;
    return false;
}


int main()
{
    memset(h,-1,sizeof h);
    memset(dist,0x3f,sizeof dist);
    scanf("%d%d",&n,&k);
    for(int i=1;i<n;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b),add(b,a);
    }
    
    L=bfs(1,-1).first;
    PII y=bfs(L,-1);
    R=y.first,D=y.second;
    memcpy(dis,dist,sizeof dist);
    
    res=(n-1)*2-D+1;

    if(k==1)
    {
        printf("%d",res);
        return 0;
    }
    
    dfs(L);
    
    int ans=0x3f3f3f3f;
    for(int j=1;j<=top;j++)
    {
        int i=path[j];
        auto y=bfs(i,-1);
        int x=y.first,len_d=y.second;
        maxl[i]=len_d;//记录最长链
        y=bfs(x,i);
        ans=min(ans,res-y.second+1);//子树内直径>=最长链
    }
    
    int gmaxl=-0x3f3f3f3f,maxv=-0x3f3f3f3f;
    for(int j=1;j<=top;j++)
    {
        int i=path[j];
        int gl=maxl[i]+dis[i],gr=maxl[i]+(D-dis[i]);
        maxv=max(gr+gmaxl-D-1,maxv);
        gmaxl=max(gmaxl,gl);
    }
    
    ans=min(ans,ans-maxv);
    
    printf("%d",ans);
    
    return 0;
}

2023/10/23 16:51
加载中...