解题思路: 该题需要考虑每条边给答案带来的贡献,通过简单的画图和思考我们可以发现,当一个节点下有偶数个叶子节点时,该节点到父亲节点的边的贡献为2,若为奇数则为1,那么最后的答案为
N
−
2
+
s
i
g
m
a
(
d
u
[
i
]
m
o
d
2
=
=
0
)
N-2+sigma(du[i]mod 2==0)
N−2+sigma(du[i]mod2==0),利用树链剖分维护即可
int n, q, rt, sum;constint N =2e5+5;struct node {int v0, v1, l, r, tag;}tr[N<<2];
vector <int> edge[N];int deg[N];int value[N];//节点值int fa[N], deep[N], son[N], siz[N];int dfn[N],top[N], id[N], tot =0;void dfs1 (int u){
siz[u]=1;for(auto v : edge[u]){if(v != fa[u]){
fa[v]= u;
deep[v]= deep[u]+1;
dfs1 (v);
value[u]+= value[v];
siz[u]+= siz[v];if(siz[v]> siz[son[u]])
son[u]= v;}}}void dfs2 (int u,int t){
top[u]= t;
dfn[u]=++ tot;
id[tot]= u;if(son[u]) dfs2 (son[u], t);for(auto v : edge[u])if(v != son[u]&& v != fa[u])
dfs2 (v, v);}void push_up (int i){
tr[i].v0 = tr[i<<1].v0 + tr[i<<1|1].v0;
tr[i].v1 = tr[i<<1].v1 + tr[i<<1|1].v1;}void push_down (int i){if(tr[i].tag){
tr[i<<1].tag ^= tr[i].tag;
tr[i<<1|1].tag ^= tr[i].tag;
swap (tr[i<<1].v0, tr[i<<1].v1);
swap (tr[i<<1|1].v0, tr[i<<1|1].v1);
tr[i].tag =0;}}void build (int i ,int l ,int r){
tr[i].l = l, tr[i].r = r, tr[i].tag =0;if(l == r){if(value[id[l]]%2) tr[i].v1 ++;else tr[i].v0 ++;return;}int mid =(l + r)>>1;
build (i <<1, l , mid);
build (i <<1|1, mid +1,r);
push_up (i);}void update (int i ,int l ,int r,int L ,int R){if(l >= L && r <= R){
swap (tr[i].v0, tr[i].v1);
tr[i].tag ^=1;return;}push_down(i);int mid =(l + r)>>1;if(L <= mid) update (i<<1,l,mid,L,R);if(R > mid) update (i<<1|1,mid+1,r,L,R);push_up(i);}void update2 (int x,int y){while(top[x]!= top[y]){if(deep[top[x]]< deep[top[y]])swap(x,y);update(1,1, n, dfn[top[x]], dfn[x]);
x = fa[top[x]];}if(deep[x]> deep[y])swap(x,y);update(1,1, n, dfn[x], dfn[y]);}intmain(void){
CLOSE;
cin >> n >> q;for(int i =1; i < n ; i ++){int u, v;
cin >> u >> v;
edge[u].pb (v);
edge[v].pb (u);
deg[u]++, deg[v]++;}for(int i =1; i <= n ; i ++)if(deg[i]==1)
value[i]=1, sum ++;for(int i =1; i <= n ; i ++)if(sz(edge[i])){
rt = i;break;}
dfs1 (rt), dfs2 (rt, rt), build (1,1,n);
vector <int> ve;while(q --){int now = sum;
ve.clear();int x, v;
cin >> x;for(int i =1; i <= x ; i ++){
cin >> v;
ve.pb(v);if(deg[v]!=1) update2 (rt, v), now ++;
deg[v]++;}if(now %2) cout <<-1<< endl;else cout << n + x -2+ tr[1].v0 << endl;for(auto it : ve){
deg[it]--;if(deg[it]!=1) update2 (rt, it);}}}
树链剖分应用一.题目链接: https://codeforces.com/problemset/problem/1403/B解题思路: 该题需要考虑每条边给答案带来的贡献,通过简单的画图和思考我们可以发现,当一个节点下有偶数个叶子节点时,该节点到父亲节点的边的贡献为2,若为奇数则为1,那么最后的答案为N−2+sigma(du[i]mod2==0)N-2+sigma(du[i]mod 2==0)N−2+sigma(du[i]mod2==0),利用树链剖分维护即可int n, q, rt, sum