[loj3176]景点划分

不妨假设\(a\le b\le c\),并钦定连通的集合为\(A,B\)

建立dfs树,取节点\(k\)满足\(sz_{k}\ge a\)\(\forall son,sz_{son}<a\)

删除\(k\)后,记\(k\)子树外的连通块为\(S\),取\(T=\complement_{V}S\),并分类讨论:

  • \(|S|<a\),则\(A,B\)均需包含\(k\),无解
  • \(a\le |S|<b\),则\(|T|\ge b\),在\(S\)\(T\)中分别得到\(A,B\)即可
  • \(|S|\ge b\),则不断将\(S\)中某个\(son\)的子树调整到\(T\)中直至\(|T|\ge a\)

由于\(sz_{son}<a\),即\(|T|<2a\),仍有\(|S|\ge b\),在\(T\)\(S\)中分别得到\(A,B\)即可

模拟实现上述过程,时间复杂度为\(O(n+m)\)

#include<bits/stdc++.h>
using namespace std;
const int N=100005;
int n,m,x,y,flag,now,a[4],id[4],dfn[N],low[N],sz[N],ans[N];
vector<int>e[N],son[N];
bool cmp(int x,int y){
    return a[x]<a[y];
}
void dfs(int k,int fa){
    int mx=0,s=0;
    dfn[k]=low[k]=++dfn[0],sz[k]=1;
    for(int i:e[k])
        if (i!=fa){
            if (dfn[i])low[k]=min(low[k],dfn[i]);
            else{
                dfs(i,k),son[k].push_back(i);
                sz[k]+=sz[i],low[k]=min(low[k],low[i]);
                if (dfn[k]<=low[i])mx=max(mx,sz[i]);
                else s+=sz[i];
            }
        }
    s+=n-sz[k];
    if (max(mx,s)<a[id[1]])flag=1;
}
void dfs_son(int k){
    if (!a[now])return;
    a[now]--,ans[k]=now;
    for(int i:son[k])dfs_son(i);
}
void dfs_e(int k){
    if ((!a[now])||(ans[k]))return;
    a[now]--,ans[k]=now;
    for(int i:e[k])dfs_e(i);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=3;i++){
        scanf("%d",&a[i]);
        id[i]=i;
    }
    sort(id+1,id+4,cmp);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&x,&y);
        x++,y++;
        e[x].push_back(y);
        e[y].push_back(x);
    }
    dfs(1,0);
    if (flag){
        for(int i=1;i<=n;i++)printf("0 ");
        return 0;
    }
    for(int i=1;i<=n;i++)
        if (sz[i]>=a[id[1]]){
            bool flag=0;
            for(int j:son[i])
                if (sz[j]>=a[id[1]]){flag=1;break;}
            if (flag)continue;
            int s=1;
            for(int j:son[i])
                if (dfn[i]<=low[j])s+=sz[j];
            if (s>=a[id[2]]){
                now=id[2],a[now]--,ans[i]=now;
                for(int j:son[i])
                    if (dfn[i]<=low[j])dfs_son(j);
                now=id[1];
                for(int j:e[i])
                    if (dfn[i]>low[j])dfs_e(j);
                break;
            }
            now=id[1],a[now]--,ans[i]=now;
            for(int j:son[i])
                if (dfn[i]<=low[j])dfs_son(j);
            for(int j:son[i])
                if (dfn[i]>low[j])dfs_son(j);
            now=id[2];
            for(int j:e[i])
                if (dfn[i]>low[j])dfs_e(j);
            break;
        }
    for(int i=1;i<=n;i++){
        if (!ans[i])ans[i]=id[3];
        printf("%d ",ans[i]);
    }
    return 0;
}
posted @ 2023-01-20 10:24  PYWBKTDA  阅读(49)  评论(0编辑  收藏  举报