JOISC 2019 合并

Posted iefnah06

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JOISC 2019 合并相关的知识,希望对你有一定的参考价值。

URL

https://loj.ac/problem/3040

简要题意

懒得写了

解法

考虑同色的两个点,它们路径上的每条边都是不能作为分割点的,不妨把路径上的点全部缩起来。这样之后所有点都是不同颜色的。

合并颜色的操作依旧是缩点,答案是(叶子个数+1)/2

实现

#include <bits/stdc++.h>
using namespace std;

#define rng(i,a,b) for(int i=int(a);i<int(b);i++)
#define rep(i,b) rng(i,0,b)
#define gnr(i,a,b) for(int i=int(b)-1;i>=int(a);i--)
#define per(i,b) gnr(i,0,b)
#define pb push_back
#define eb emplace_back
#define bg begin()
#define ed end()
#define all(x) (x).bg,(x).ed
#define si(x) int((x).size())
#define mp make_pair
#define a first
#define b second

#ifdef LOCAL
#define dmp(x) cerr<<__LINE__<<" "<<#x<<" "<<x<<endl
#else
#define dmp(x) void(0)
#endif

template<class t,class u> void chmax(t&a,u b){if(a<b)a=b;}
template<class t,class u> void chmin(t&a,u b){if(b<a)a=b;}

template<class t> using vc=vector<t>;
template<class t> using vvc=vc<vc<t>>;

using ll=long long;
using uint=unsigned int;
using pi=pair<int,int>;
using vi=vc<int>;

int topbit(signed t){
    return t==0?-1:31-__builtin_clz(t);
}
int topbit(ll t){
    return t==0?-1:63-__builtin_clzll(t);
}

struct unionfind{
    vc<int> p;
    unionfind(int n):p(n,-1){}
    int find(int a){
        return p[a]<0?a:(p[a]=find(p[a]));
    }
    void mg(int a,int b){
        p[find(a)]=find(b);
    }
};

const int nmax=5.1e5;

vi g[nmax];
int par[nmax];
int dep[nmax];

vi state[nmax];
int deg[nmax];

void dfs(int v,int p){
    par[v]=p;
    for(int to:g[v])if(to!=p){
        dep[to]=dep[v]+1;
        dfs(to,v);
    }
}

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int n,k;cin>>n>>k;
    rep(i,n-1){
        int a,b;cin>>a>>b;a--,b--;
        g[a].pb(b);
        g[b].pb(a);
    }
    
    par[0]=-1;
    dep[0]=0;
    dfs(0,-1);

    rep(i,n){
        int s;cin>>s;s--;
        state[s].pb(i);
    }

    unionfind uf(n);
    auto mg=[&](int a,int b)->void{
        a=uf.find(a);
        b=uf.find(b);
        while(a!=b){
            if(dep[a]<dep[b])swap(a,b);
            uf.mg(a,par[a]);
            a=uf.find(par[a]);
        }
    };
    rep(i,k){
        assert(si(state[i]));
        rng(j,1,si(state[i]))
            mg(state[i][0],state[i][j]);
    }

    rep(i,n)
        for(int j:g[i])if(dep[i]<dep[j]&&uf.find(i)!=uf.find(j)){
            deg[uf.find(i)]++;
            deg[uf.find(j)]++;
        }
    int cnt=0;
    rep(i,n)if(uf.find(i)==i&&deg[i]==1)cnt++;
    int ans=(cnt+1)/2;
    cout<<ans<<'
';
}

以上是关于JOISC 2019 合并的主要内容,如果未能解决你的问题,请参考以下文章

JOISC2019 穿越时空 Bitaro

[JOISC2014]たのしい家庭菜園

4.3 合并重复的条件执行片段

JOISC 2017 题解

JOISC2020 自闭记

[JOISC2014]水筒