题目描述
给定一棵由 n 个结点组成的树以及 m 个不重复的无序数对 (a1, b1), (a2, b2), . . . , (am, bm),其中 ai 互不相同,bi 互不相同,ai ≠ bj(1 ≤ i, j ≤ m)。 小明想知道是否能够选择一条树上的边砍断,使得对于每个 (ai , bi) 满足 ai和 bi 不连通,如果可以则输出应该断掉的边的编号(编号按输入顺序从 1 开始),否则输出 -1.
输入格式
一行一个整数,表示答案,如有多个答案,输出编号最大的一个。
输出
行一个整数,表示答案,如有多个答案,输出编号最大的一个。
思路
我们考虑给u->v经过得边边权加一代表这条边我们经过一次同理可得如果边权是m代表我们经过m次也就是如果断掉这条边经过这条边的两个点将无法联通
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define int long long
#define endl '\n'
#define pb push_back
#define NO cout << "NO" << endl;
#define YES cout << "YES" << endl;
#define fi first
#define se second
#define all(x) (x).begin(),(x).end()
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,a,n) for (int i=n;i>=a;i--)
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<VI> VII;
ll MOD = 998244353;
ll powmod(ll a,ll b) {ll res=1;a%=MOD; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%MOD;a=a*a%MOD;}return res;}
const int N = 2e5 + 10;
int w[N];
int n,m;
int son[N],id[N],fa[N],cnt,dep[N],siz[N],top[N],wt[N];
vector<int> v[N];
int f[N << 2],Lazy[N << 2];
void Built(int k,int l,int r) {
if( l == r) {
f[k] = wt[l];
f[k] %= MOD;
// cout << f[k] << endl;
return;
}
int m = l + r >> 1;
Built(k<<1,l,m);
Built(k<<1|1,m+1,r);
f[k] = f[k << 1] + f[k << 1|1];
f[k] %= MOD;
}
void update(int k,int l,int r,int L,int R,int s)
{
if( l == L&& r == R)
{
Lazy[k] += s;
return;
}
if(Lazy[k]) {
Lazy[k <<1] += Lazy[k];
Lazy[k << 1|1] += Lazy[k];
Lazy[k] = 0;
}
int m = (l + r) >> 1;
if(R <= m) update(k << 1,l,m,L,R,s);
else
{
if(L > m) update(k << 1|1,m+1,r,L,R,s);
else update(k << 1,l,m,L,m,s),update(k <<1|1,m+1,r,m+1,R,s);
}
f[k] = f[k << 1] + Lazy[k << 1] *(m - l + 1) + f[k << 1 | 1] + Lazy[k <<1|1] * (r - m);
f[k] %= MOD;
}
int calc(int k,int l,int r,int x,int y)
{
if(l == x && r == y){
return (f[k] + Lazy[k] * (r - l + 1)) % MOD;
}
if(Lazy[k]) Lazy[k << 1] += Lazy[k], Lazy[k << 1|1] += Lazy[k],Lazy[k] = 0;
int res = 0;
int m = (l + r) >> 1;
if(y <= m) res = calc(k << 1,l,m,x,y);
else {
if(x > m) res = calc(k<<1|1,m+1,r,x,y);
else res = calc(k<<1,l,m,x,m) + calc(k<<1|1,m+1,r,m+1,y);
}
f[k] = f[k << 1] + Lazy[k << 1] *(m - l + 1) + f[k << 1 | 1] + Lazy[k <<1|1] * (r - m);
return res % MOD;
}
void dfs1(int x,int f,int deep) { // 找到每个结点的子节点数量和重儿子
dep[x] = deep;
fa[x] = f;
siz[x] = 1;
int maxson = -1;
for(auto u : v[x]) {
if(u == f) continue;
dfs1(u,x,deep + 1);
siz[x] += siz[u];
if(siz[u] > maxson) {
son[x] = u;
maxson = siz[u];
}
}
}
void dfs2(int x,int topf) {
id[x] = ++cnt;
wt[cnt] = w[x];
top[x] = topf;
if(!son[x]) return;
dfs2(son[x],topf);
for(auto u : v[x]) {
if(u == fa[x] || u == son[x]) continue;
dfs2(u,u);
}
}
int qRange(int x,int y){ // x -> y 区间求和
int ans=0;
while(top[x] != top[y]){//当两个点不在同一条链上
if(dep[top[x]] < dep[top[y]])swap(x,y);//把x点改为所在链顶端的深度更深的那个点
ans += calc(1,1,n,id[top[x]],id[x]);//ans加上x点到x所在链顶端 这一段区间的点权和
ans %= MOD;//按题意取模
x=fa[top[x]];//把x跳到x所在链顶端的那个点的上面一个点
}
//直到两个点处于一条链上
if(dep[x] > dep[y])swap(x,y);//把x点深度更深的那个点
int res = 0;
ans += calc(1,1,n,id[x],id[y]);//这时再加上此时两个点的区间和即可
return ans % MOD;
}
void updRange(int x,int y,int k){// 区间修改
k %= MOD;
while(top[x] != top[y]){
if(dep[top[x]] < dep[top[y]]) swap(x,y);
update(1,1,n,id[top[x]],id[x],k);
x = fa[top[x]];
}
if(dep[x] > dep[y])swap(x,y);
update(1,1,n,id[x],id[y],k);
}
int qSon(int x){ //单点查询
int res = 0;
return calc(1,1,n,id[x],id[x] + siz[x]-1);//子树区间右端点为id[x]+siz[x]-1
// return res;
}
void updSon(int x,int k) { // 更新子树
update(1,1,n,id[x],id[x] + siz[x]-1,k);//
// update(1,1,n,id[x],id[x],k); // 更新单个节点
}
void solve()
{
cin >> n >> m;
vector<PII> a(n + 1);
rep (i, 1, n - 1) {
int x, y; cin >> x >> y;
a[i] = {x, y};
v[x].pb(y);
v[y].pb(x);
}
int r = 1;
dfs1(r,0,1), dfs2(r,r);
Built(1, 1, n);
rep (i, 1, m) {
int x, y; cin >> x >> y;
updRange(x, y, 1);
}
VI s(n + 1);
rep (i, 1, n) s[i] = qRange(i, i);
// rep (i, 1, n) cout << s[i] << " \n"[i == n];
per (i, 1, n - 1) {
auto [x, y] = a[i];
if (s[x] == m && s[y] == m) {
cout << i << endl;
return;
}
}
cout << -1 << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
// int T;cin >> T;
// while ( T -- )
solve();
return 0;
}