第十四届蓝桥杯省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';
}
相关推荐
程序员三藏37 分钟前
Selenium+python自动化测试:解决无法启动IE浏览器及报错问题
自动化测试·软件测试·python·selenium·测试工具·职场和发展·测试用例
黑客影儿5 小时前
黑客哲学之学习笔记系列(三)
笔记·学习·程序人生·安全·职场和发展·网络攻击模型·学习方法
熬了夜的程序员5 小时前
【LeetCode】16. 最接近的三数之和
数据结构·算法·leetcode·职场和发展·深度优先
Miraitowa_cheems5 小时前
LeetCode算法日记 - Day 15: 和为 K 的子数组、和可被 K 整除的子数组
java·数据结构·算法·leetcode·职场和发展·哈希算法
火车叨位去19492 天前
力扣top100(day04-05)--堆
算法·leetcode·职场和发展
qq_513970442 天前
力扣 hot100 Day76
算法·leetcode·职场和发展
程序员曦曦3 天前
10:00开始面试,10:06就出来了,问的问题有点变态。。。
自动化测试·软件测试·功能测试·程序人生·面试·职场和发展
是乐谷3 天前
阿里云杭州 AI 产品法务岗位信息分享(2025 年 8 月)
java·人工智能·阿里云·面试·职场和发展·机器人·云计算
天才测试猿3 天前
常见的Jmeter压测问题
自动化测试·软件测试·python·测试工具·jmeter·职场和发展·压力测试
墨染点香3 天前
LeetCode 刷题【43. 字符串相乘】
算法·leetcode·职场和发展