第十四届蓝桥杯省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';
}
相关推荐
AlenTech10 小时前
207. 课程表 - 力扣(LeetCode)
算法·leetcode·职场和发展
练习时长一年11 小时前
LeetCode热题100(杨辉三角)
算法·leetcode·职场和发展
_OP_CHEN14 小时前
【算法基础篇】(四十五)裴蜀定理与扩展欧几里得算法:从不定方程到数论万能钥匙
算法·蓝桥杯·数论·算法竞赛·裴蜀定理·扩展欧几里得算法·acm/icpc
我命由我1234514 小时前
Photoshop - Photoshop 工具栏(58)锐化工具
学习·ui·职场和发展·求职招聘·职场发展·学习方法·photoshop
踩坑记录14 小时前
leetcode hot100 438. 找到字符串中所有字母异位词 滑动窗口 medium
leetcode·职场和发展
YuTaoShao15 小时前
【LeetCode 每日一题】1458. 两个子序列的最大点积——(解法三)状态压缩
算法·leetcode·职场和发展
橘颂TA15 小时前
【剑斩OFFER】算法的暴力美学——leetCode 946 题:验证栈序列
c++·算法·leetcode·职场和发展·结构与算法
wen__xvn15 小时前
力扣第 484 场周赛
算法·leetcode·职场和发展
YuTaoShao15 小时前
【LeetCode 每日一题】865. 具有所有最深节点的最小子树——(解法一)自顶向下
算法·leetcode·职场和发展
2301_8008951016 小时前
hh的蓝桥杯每日一题--拔河
职场和发展·蓝桥杯