思路:
首先隨意欽定一個不是葉子節點的節點為根節點。
然後考慮對於一個不是根節點的點 \(u\),肯定需要至少一個葉子去與 \(u\) 子樹之外的葉子節點配對。
考慮 \(u\) 到 \(fa_u\) 的這條邊,首先至少有一個葉子節點穿過,然後設 \(p_u\) 表示 \(u\) 中的葉子節點個數:
-
若 \(p_u\) 為偶,在一個葉子節點往外傳後還剩奇數個,兩兩配對後還剩一個葉子節點,也需要往外傳經過 \(u \to fa_u\) 的這條邊。
-
否則 \(p_u\) 為奇時,在一個葉子節點往外傳後還剩偶數個,可以完美兩兩配對。
那麼對於 \(u \to fa_u\) 的這條邊,經過這條邊的葉子節點個數為 \(1 + [p_u \bmod 2=0]\)。
則總答案為:
\[\sum_{u \ne rt} 1 + [p_u \bmod 2 = 0] = (n-1) + \sum_{u \ne rt} [p_u \bmod 2 = 0]
\]
考慮將 \(u \ne rt\) 給去掉,可以方便一些計算。
因為若 \(p_{rt}\) 不為偶數,就無法使得所有葉子節點配對,即無解,所以在有解的情況下 \([p_{rt} \bmod 2 = 0] = 1\),則需要將前面 \(-1\)。
則原式化為:
\[n -2 + \Big(\sum_u[p_u \bmod 2 = 0]\Big)
\]
則每次在 \(u\) 處新增一個葉子節點,就相當於將 \(u\) 到根節點的 \(p_u \bmod 2\) 的值取反。
那麼直接樹剖維護即可,時間複雜度為 \(O(\Big(\sum D_i\Big) \log^2 n)\)。
要注意一下細節:在葉子節點下新增新節點,是沒有貢獻的(即不需要翻轉),於是我們可以動態維護每個點的度數。
完整程式碼:
#include<bits/stdc++.h>
#define Add(x,y) (x+y>=mod)?(x+y-mod):(x+y)
#define lowbit(x) x&(-x)
#define pi pair<ll,ll>
#define pii pair<ll,pair<ll,ll>>
#define iip pair<pair<ll,ll>,ll>
#define ppii pair<pair<ll,ll>,pair<ll,ll>>
#define fi first
#define se second
#define full(l,r,x) for(auto it=l;it!=r;it++) (*it)=x
#define Full(a) memset(a,0,sizeof(a))
#define open(s1,s2) freopen(s1,"r",stdin),freopen(s2,"w",stdout);
#define For(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
typedef double db;
typedef unsigned long long ull;
typedef long long ll;
bool Begin;
const ll N=1e5+10;
inline ll read(){
ll x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')
f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return x*f;
}
inline void write(ll x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
write(x/10);
putchar(x%10+'0');
}
ll n,m,s,q,x,h,rt;
ll du[N];
bool f[N];
vector<ll> E[N];
stack<ll> T;
void add(ll u,ll v){
E[u].push_back(v);
E[v].push_back(u);
du[u]++,du[v]++;
}
namespace Seg{
struct Node{
ll len;
ll l,r;
ll data;
bool tag;
}X[N<<2];
void pushup(ll k){
X[k].data=X[k<<1].data+X[k<<1|1].data;
}
void rev(ll k){
X[k].data=X[k].len-X[k].data;
X[k].tag^=1ll;
}
void push_down(ll k){
if(X[k].tag){
rev(k<<1);
rev(k<<1|1);
X[k].tag=0;
}
}
void build(ll k,ll l,ll r){
X[k].len=r-l+1;
X[k].l=l,X[k].r=r;
if(l==r)
return ;
ll mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
}
void update(ll k,ll i){
if(X[k].l==i&&i==X[k].r){
X[k].data=1;
return ;
}
push_down(k);
ll mid=(X[k].l+X[k].r)>>1;
if(i<=mid)
update(k<<1,i);
else
update(k<<1|1,i);
pushup(k);
}
void rev(ll k,ll l,ll r){
if(X[k].l==l&&r==X[k].r){
rev(k);
return ;
}
push_down(k);
ll mid=(X[k].l+X[k].r)>>1;
if(r<=mid)
rev(k<<1,l,r);
else if(l>mid)
rev(k<<1|1,l,r);
else{
rev(k<<1,l,mid);
rev(k<<1|1,mid+1,r);
}
pushup(k);
}
ll sum(){
return X[1].data;
}
};
namespace Tree{
ll cnt=0;
ll siz[N],w[N],z[N],fa[N],d[N],t[N],dfn[N];
void dfs1(ll u,ll f){
siz[u]=1;
for(auto v:E[u]){
if(v==f)
continue;
fa[v]=u;
d[v]=d[u]+1;
dfs1(v,u);
siz[u]+=siz[v];
if(siz[v]>siz[z[u]])
z[u]=v;
}
}
void dfs2(ll u,ll k){
t[u]=k;
dfn[u]=++cnt;
if(!z[u])
return ;
dfs2(z[u],k);
for(auto v:E[u]){
if(v==fa[u]||v==z[u])
continue;
dfs2(v,v);
}
}
void dfs3(ll u){
if(du[u]==1){
s++;
w[u]=1;
return ;
}
for(auto v:E[u]){
if(v==fa[u])
continue;
dfs3(v);
w[u]+=w[v];
}
}
void init(){
Seg::build(1,1,n);
dfs1(rt,rt);
dfs2(rt,rt);
dfs3(rt);
For(i,1,n)
if((w[i]&1ll)^1ll)
Seg::update(1,dfn[i]);
}
void rev(ll u,ll v){
while(t[u]!=t[v]){
if(d[t[u]]<d[t[v]])
swap(u,v);
Seg::rev(1,dfn[t[u]],dfn[u]);
u=fa[t[u]];
}
if(d[u]>d[v])
swap(u,v);
Seg::rev(1,dfn[u],dfn[v]);
}
};
bool End;
int main(){
n=read(),q=read();
for(int u,v,i=1;i<n;i++){
u=read(),v=read();
add(u,v);
}
For(i,1,n){
if(du[i]!=1){
rt=i;
break;
}
}
Tree::init();
while(q--){
h=0;
m=read();
For(i,1,m){
x=read();
if(du[x]==1)
s--;
else{
Tree::rev(x,rt);
f[x]^=1ll;
}
s++;
du[x]++;
T.push(x);
}
if(s&1ll)
puts("-1");
else{
write(h+n+m-2+Seg::sum());
putchar('\n');
}
while(!T.empty()){
x=T.top();
s--;
du[x]--;
if(du[x]==1)
s++;
if(f[x]){
Tree::rev(rt,x);
f[x]=0;
}
T.pop();
}
}
//cerr<<'\n'<<abs(&Begin-&End)/1048576<<"MB";
return 0;
}