王冰冰的砍树问题
题目:
给你一棵由 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;
}

浙公网安备 33010602011771号