第十四届蓝桥杯省B.砍树

第十四届蓝桥杯省B.砍树

题目

题目解析及思路

考虑一对无序数对的点 x和 y,如果我们砍掉某条边可以让这两个点不连通 ,那么这条边一定是从 x到 y 路径上的一点 ,我们可以让从 x到 y 路径的边权值都加1 。这个操作我们可以使用树上差分 。 对于 m个无序数对我们都如此操作,最后如果某条边的权值为 m 则说明它符合条件,我们选出符合条件编号最大的那条边就是答案,如果没有权值为 m的边则说明无解。

树上差分

代码

cpp 复制代码
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define pii pair<int,int>
#define ms(s,x) memset(s, x, sizeof(s))
using namespace std;
typedef pair<int,int> PII;
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const int N = 200010;

int n, m;
vector<int> e[N];
int depth[N], fa[N][16];
int f[N];
int root;
int ans;
map<PII, int> mp;

//lca板子
void bfs(int root){
    memset(depth,0x3f,sizeof(depth));
    depth[0] = 0,depth[root] = 1;
    queue<int> q;
    q.push(root);
    
    while(!q.empty()){
        int t = q.front();
        q.pop();
        for(int j:e[t]){
            if(depth[j] > depth[t] + 1){
                depth[j] = depth[t] + 1;
                q.push(j);
                fa[j][0] = t;
                for(int k=1;k<=15;k++){
                    fa[j][k] = fa[fa[j][k-1]][k-1];
                }
            }
        }
    }
}

int lca(int a,int b){
    if(depth[a] < depth[b]) swap(a,b);
    for(int k=15;k>=0;k--){
        if(depth[fa[a][k]] >= depth[b]){
            a = fa[a][k];
        }
    }
    if(a == b) return a;
    for(int k=15;k>=0;k--){
        if(fa[a][k] != fa[b][k]){
            a = fa[a][k];
            b = fa[b][k];
        }
    }
    return fa[a][0];
}
//对树上差分数组f进行dfs求和
int dfs(int u,int fa){
    int res = f[u];
    for(auto v:e[u]){
        if(v == fa) continue;
        int g = dfs(v,u);
        if(g == m){
            ans = max(ans,mp[{v,u}]);
        }
        res += g;
    }
    return res;
}
signed main(){
    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(false);
    
    ans = 0;
    cin>>n>>m;
    for(int i=0;i<n-1;i++){
        int u,v;
        cin>>u>>v;
        mp[{u,v}] = mp[{v,u}] = i+1;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    //lca
    bfs(1);
    //树上差分
    for(int i=0;i<m;i++){
        int u,v;
        cin>>u>>v;
        int z = lca(u,v);
        f[u] ++;
        f[v] ++;
        f[z] -= 2;
    }
    dfs(1,-1);
    cout << (ans == 0 ? -1 : ans) << '\n';
}
相关推荐
重庆小透明20 分钟前
【搞定面试之mysql】第一篇:mysql的优化和索引
mysql·面试·职场和发展
灰色小旋风4 小时前
力扣20有效的括号(C++)
c++·算法·leetcode·职场和发展
keep intensify5 小时前
最小路径和
算法·leetcode·职场和发展
includei6 小时前
【社招】面试_中科飞思_前端工程师
前端·面试·职场和发展
多打代码6 小时前
2026.03.23 最长递增子序列 & 最长连续递增序列 & 最长公共子序列
算法·leetcode·职场和发展
闻缺陷则喜何志丹6 小时前
【动态规划+前缀和+化环为链】P8810 [蓝桥杯 2022 国 C] 数组个数|普及+
c++·算法·前缀和·蓝桥杯·动态规划·洛谷·化环为链
爱敲代码的菜菜6 小时前
【面试】软件测试
面试·职场和发展
红云梦8 小时前
用大模型生成结构化面试评估报告:Prompt工程实战
ai·面试·职场和发展·prompt
羊小猪~~8 小时前
算法/力扣--数组典型题目
c语言·c++·python·算法·leetcode·职场和发展·求职招聘