P6805 [CEOI2020] 春季大掃除

rgw2010發表於2024-08-16

思路:

首先隨意欽定一個不是葉子節點的節點為根節點。

然後考慮對於一個不是根節點的點 \(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;
}

相關文章