Favorite Colors —— 并查集+dfs

应该能进

题意:

现在有n个数,然后有一些有向边。现在需要将每个数涂上色,要求如下:
1.颜色种类尽可能多
2.如果两个点指向相同颜色的点,那么这两个点的颜色相同
3.最终构造出来的颜色按顺序输出时字典序最小

题解:

我们可以发现的就是如果有一个点的入度>=2那么这些儿子的点的颜色相同,然后再指向这些儿子的点的所有颜色相同,于是我们就需要dfs去做并查集,然后多个儿子的话,我们需要将儿子的所有儿子都放到根那里,此时就需要启发式合并,这样的时间复杂度最大就是 O ( n l o g n ) O(nlogn) 的。
直到做到某个点的儿子数<=1

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int fa[N];
int finds(int x){return fa[x]<0?x:fa[x]=finds(fa[x]);}
vector<int>vec[N],tmp;
void dfs(int x){
    if(vec[x].size()<2)return ;
    int rt=finds(vec[x][0]);
    for(int i=1;i<vec[x].size();i++){
        int ne=finds(vec[x][i]);
        if(ne==rt)continue;
        if(fa[rt]<=fa[ne]){
            fa[rt]+=fa[ne];
            fa[ne]=rt;
            for(auto j:vec[ne])
                vec[rt].push_back(j);
            vec[ne].clear();
        }
        else{
            fa[ne]+=fa[rt];
            fa[rt]=ne;
            for(auto j:vec[rt])
                vec[ne].push_back(j);
            vec[rt].clear();
            rt=ne;
        }
    }
    vec[x].clear();
    vec[x].push_back(rt);
    dfs(rt);
}
int col[N];
int main()
{
    memset(fa,-1,sizeof(fa));
    int n,m,x,y;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
        scanf("%d%d",&x,&y),vec[x].push_back(y);
    for(int i=1;i<=n;i++)
        dfs(i);
    int cnt=0;
    for(int i=1;i<=n;i++){
        int f=finds(i);
        if(!col[f])
            col[f]=++cnt;
        printf("%d\n",col[f]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/tianyizhicheng/article/details/107289805