第十四届蓝桥杯省B.砍树
第十四届蓝桥杯省B.砍树
题目
题目解析及思路
考虑一对无序数对的点 x和 y,如果我们砍掉某条边可以让这两个点不连通,那么这条边一定是从 x到 y 路径上的一点,我们可以让从 x到 y 路径的边权值都加1。这个操作我们可以使用树上差分。 对于 m个无序数对我们都如此操作,最后如果某条边的权值为 m 则说明它符合条件,我们选出符合条件编号最大的那条边就是答案,如果没有权值为 m的边则说明无解。
树上差分
代码
#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);}//lcabfs(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';
}