王冰冰的砍树问题

题目:

给你一棵由 n 个结点组成的树和 m 个不重复的无序数对 (a1,b1),(a2,b2),...,(am,bm),注意对于其中每一个i,ai和bi都不相同,ai,bj (1≤i,j≤m)。

小憨憨王冰冰想知道是否能够选择一条树上的边砍断,使得对于每个 (ai,bi) 满足 ai​ 和 bi不连通,如果可以则输出可以断掉的边的编号最大的一个(编号按输入顺序从 1 开始),如果不可以输出 −1。

题意:

给定一颗树,要求消除一条边,使得m个两两匹配的节点都无法连通

思路:

发现将所有两两匹配的节点的简单路径画出,当经过的边次数等于m次时,消除掉该边恰好能使m个匹配节点不连通

如何统计每个简单路径经过边的累加次数?

树上LCA+差分

对于一对节点,从两个节点分别出发,则cnt[a]++,cnt[b]++

到其lca完成边的遍历,则cnt[lca(a,b)]-=2

dfs进行前缀和查找答案即可

int id=1;
struct edge{
    int v;int idx;
};
vector<edge>e[maxn];
int f[maxn];
int dep[maxn];
int lca(int a,int b){
    while(a!=b){
        if(dep[a]>dep[b])a=f[a];else b=f[b];
    }
    return a;
}//lca朴素求法



void dfs(int u,int fa,int depth){
    dep[u]=depth;
    for(auto x:e[u]){
        int v=x.v,idx=x.idx;
        if(v==fa)continue;
        f[v]=u;
        dfs(v,u,depth+1);
    }   
}
int n,m;
int ans=-1;
int cnt[maxn];
int dfs2(int u,int fa){
    int sum=cnt[u];
    
    for(auto ed:e[u]){
        int v=ed.v,idx=ed.idx;
        if(v==fa)continue;
        int t=dfs2(v,u);

        if(t==m){
            ans=max(ans,idx);
        }
        sum+=t;
    }

    return sum;
}

void solve(){
    cin>>n>>m;
    for(int i=1;i<=n-1;i++){
        int u,v;cin>>u>>v;
        e[u].pb((edge){v,id});e[v].pb((edge){u,id++});
    }
    dfs(1,0,0);
    for(int i=1;i<=m;i++){
        int u,v;cin>>u>>v;
        cnt[u]++;cnt[v]++;cnt[lca(u,v)]-=2;
    }
    
    int k=dfs2(1,0);
    
    cout<<ans<<endl;
}
posted @ 2025-04-22 21:52  Marinaco  阅读(21)  评论(0)    收藏  举报
//雪花飘落效果