CF1218G Alpha planetary system 题解

Part 1

\(w_x\) 表示点 \(x\) 的权值 \(\bmod 3\)\(c_x\) 表示 \(x\) 的所属集合编号(\(c_x \in \{0,1,2\}\)),\(v_i\) 表示第 \(i\) 条边的权值。

一个直接的想法是使所有 \(w_x=c_x\),当然这不一定能做到,具体见下文。

首先,根据套路,随便建一颗生成树出来。设根为 \(rt\)

先将所有非树边权值设为 \(3\)。对于点 \(u\),若其子树内所有树边权值都确定了,则 \(u\) 到父亲的树边的权值可以唯一确定。

然而,\(rt\) 没有到父亲的边,此时要做出调整:

  1. 如果此时 \(w_{rt}=c_{rt}\),则方案已经合法。
  2. 否则,我们需要找到包含 \(rt\) 的一个环进行调整。

Part 2

提取出包含 \(rt\) 的一个环,设环上的编号依次为 \(e_1,e_2,\dots,e_k\),其中 \(e_1,e_2\) 两条边均有一个端点是 \(rt\)

偶环是没用的,因为在偶环上对权值调整只能形如 \(v_{e_1}+1,v_{e_2}+2,v_{e_3}+1,v_{e_4}+2,\dots\),无法改变任何一点的权值。

奇环是有用的,考虑如下调整:

  • \(w_{rt}+1\equiv c_{rt} \pmod 3\),执行 \(v_{e_1}+2,v_{e_2}+2,v_{e_3}+1,v_{e_4}+2,v_{e_5}+1,\dots\)。显然环上除了 \(rt\) 其他点的权值均未改变。
  • \(w_{rt}+2\equiv c_{rt} \pmod 3\),执行 \(v_{e_1}+1,v_{e_2}+1,v_{e_3}+2,v_{e_4}+1,v_{e_5}+2,\dots\)

因此,当原图中存在奇环,\(rt\) 取奇环上的任意一点,一定可以构造出合法方案。

Part 3

如果没有奇环呢?容易想到原图是二分图

考虑重新将所有点划分为 \(2\) 个集合,这可以通过二分图染色实现。设 \(c_x\) 表示 \(x\) 新的所属集合编号(\(c_x \in \{1,2\}\))。

不失一般性地设 \(c_{rt}=1\),还是像 Part 1 那样将处理树边,最后考虑 \(rt\) 的情况:

  1. \(w_{rt} \ne 2\)。此时方案已经合法。因为对于与 \(rt\) 之间有边的点 \(u\) 必有 \(w_u=2 \ne w_{rt}\)
  2. \(rt\) 的度数 \(=1\)。此时方案已经合法。设与 \(rt\) 之间有边的点为 \(u\),显然 \(u\) 的度数 \(>1\),则 \(u\) 的权值必然 \(>\) \(rt\) 的权值。
  3. \(w_{rt}=2\)\(rt\) 的度数 \(>1\)。选出与 \(rt\) 之间有边的两个点 \(u,v\),将 \((rt,u),(rt,v)\) 两条边的权值 \(+1\) 即可。调整后 \(w_{rt}=1,w_u=w_v=0\),可以证明满足要求。

代码实现不难。

#include <bits/stdc++.h>

using namespace std;

using i64=long long;
using u64=unsigned long long;
using db=double;
using pii=pair<int,int>;
using vi=vector<int>;

template<typename T>
inline T read(){
    T x=0,f=0;char ch=getchar();
    while(!isdigit(ch)) f|=(ch=='-'),ch=getchar();
    while(isdigit(ch)) x=x*10+(ch-'0'),ch=getchar();
    return f?-x:x;
}

#define rdi read<int>
#define rdi64 read<i64>
#define fi first
#define se second
#define pb push_back

const int N=2e5+10;

int n,m,typ[N];
char s[N];

struct Edge{int to,nxt,fl,w;}e[N];
int head[N],tot=1,deg[N];

void add_e(int x,int y){
    e[++tot]={y,head[x],0,0};
    head[x]=tot,++deg[x];
}

bool odd_lp;
int col[N];
void dfs(int x,int c=1){
    col[x]=c;
    for(int i=head[x];i;i=e[i].nxt){
        int y=e[i].to;
        if(!col[y]) e[i].fl=e[i^1].fl=1,dfs(y,3-c);
        else if(col[y]==col[x]) odd_lp=true;
    }
}

namespace S1{
    int sum[N];
    void dfs1(int x,int fa){
        for(int i=head[x];i;i=e[i].nxt){
            if(!e[i].fl) continue;
            int y=e[i].to;
            if(y!=fa) dfs1(y,x),sum[x]+=e[i].w;
        }
        for(int i=head[x];i;i=e[i].nxt){
            if(e[i].fl&&e[i].to==fa){
                e[i].w=e[i^1].w=(col[x]+3-sum[x]%3)%3;
                sum[x]=col[x];break;
            }
        }
    }
    void solve(){
        int rt=find(col+1,col+n+1,1)-col;
        dfs1(rt,0);
        if(deg[rt]>1&&sum[rt]%3==2){
            int i1=head[rt],i2=e[i1].nxt;
            e[i1].w++,e[i1^1].w++,e[i2].w++,e[i2^1].w++;
        }
    }
}

namespace S2{
    int rt,u,sum[N],tofa[N];
    void dfs1(int x,int fa){
        for(int i=head[x];i;i=e[i].nxt){
            if(!e[i].fl) continue;
            int y=e[i].to;
            if(y!=fa) dfs1(y,x),sum[x]+=e[i].w;
        }
        for(int i=head[x];i;i=e[i].nxt){
            if(e[i].fl&&e[i].to==fa){
                e[i].w=e[i^1].w=(typ[x]+3-sum[x]%3)%3;
                sum[x]=typ[x],tofa[x]=i;
                break;
            }
        }
    }

    void adjust(){
        if(sum[rt]%3==typ[rt]%3) return;
        vi cyc;int x=u;
        while(x!=rt) cyc.pb(tofa[x]),x=e[tofa[x]].to;
        for(int i=head[rt];i;i=e[i].nxt)
            if(!e[i].fl&&e[i].to==u) {cyc.insert(cyc.begin(),i);break;}
        int val=(sum[rt]+1)%3==typ[rt]%3?2:1;
        for(auto id:cyc) e[id].w+=val,e[id^1].w+=val,val=3-val;
    }

    void solve(){
        for(int x=1;x<=n;x++){
            bool fl=0;
            for(int i=head[x];i;i=e[i].nxt)
                if(col[e[i].to]==col[x]){
                    fl=1,rt=x,u=e[i].to;
                    break;
                }
            if(fl) break;
        }
        dfs1(rt,0),adjust();
    }
}

void output(){
    for(int i=2;i<=tot;i+=2){
        int x=e[i^1].to,y=e[i].to,w=(e[i].w+2)%3+1;
        cout<<x-1<<' '<<y-1<<' '<<w<<'\n';
    }
}

int main(){
    n=rdi(),m=rdi();
    scanf("%s",s+1);
    for(int i=1;i<=n;i++) typ[i]=s[i]-'X'+1;
    for(int i=1;i<=m;i++){
        int x=rdi()+1,y=rdi()+1;
        add_e(x,y),add_e(y,x);
    }
    dfs(1);
    if(odd_lp) S2::solve();
    else S1::solve();
    output();
    return 0;
}
posted @ 2022-12-08 18:18  Zesty_Fox  阅读(95)  评论(0编辑  收藏  举报