【学习笔记】CF1610F Mashtali: a Space Oddysey

感觉智商还是不太够😅

正常人的做法:答案上界是显然的,就是 ∑ w \sum w ∑w为奇数的点的个数,因为限制很松。但是直接构造比较棘手,考虑两条边 ( x , v ) (x,v) (x,v)和 ( v , y ) (v,y) (v,y),如果这两条边的权值也相同,那么可以在原图中将 ( x , v ) (x,v) (x,v)和 ( v , y ) (v,y) (v,y)删掉,然后加入 ( x , y ) (x,y) (x,y)这条边。这样每次操作后,边的数目会减少 1 1 1。一直这样操作下去,最后每个点的度数不会超过 2 2 2,因此是若干环和链,显然从链的端点或者环上任意一点开始定向即可。

具体实现方式是:枚举 x x x以及出边 v v v,然后再找到 v v v的一条出边 y y y,将 ( x , v ) (x,v) (x,v)和 ( v , y ) (v,y) (v,y)删掉,加入边 ( x , y ) (x,y) (x,y),然后 v v v赋值成 y y y,继续寻找 y y y的出边。写代码的时候要先把 ( x , v ) (x,v) (x,v)这条边删掉,直到 x x x的所有出边都扩展完了过后再加回来。最后还原方案只需建立二叉树然后从根节点开始遍历即可(和 kruskal \text{kruskal} kruskal重构树比较类似)。

复杂度 O ( n + m ) O(n+m) O(n+m)。但是比较难写,估计要调半天。

聪明人的做法:考虑欧拉回路。本质上就是利用了回路上出边和入边数目相同来构造,但是这道题的建图方式比较难。

考虑建立 2 n + 1 2n+1 2n+1个点(因为 1 1 1和 2 2 2其实本质上是对称的,所以把点复制一遍),建边方式如下:

1.1 1.1 1.1 对于边权为 1 1 1的边 ( u , v ) (u,v) (u,v),加入边 ( u , v ) (u,v) (u,v)
1.2 1.2 1.2 对于边权为 2 2 2的边 ( u , v ) (u,v) (u,v),加入边 ( u + n , v + n ) (u+n,v+n) (u+n,v+n)
1.3 1.3 1.3 设 d i ( j ) d_i(j) di(j)表示 j j j连了多少条度为 i i i的边,如果 d 1 ( u ) d_1(u) d1(u)和 d 2 ( u ) d_2(u) d2(u)都为奇数,加入边 ( u , u + n ) (u,u+n) (u,u+n);如果只有 d 1 ( u ) d_1(u) d1(u)为奇数,加入边 ( u , 2 n + 1 ) (u,2n+1) (u,2n+1);如果只有 d 2 ( u ) d_2(u) d2(u)为奇数,加入边 ( u + n , 2 n + 1 ) (u+n,2n+1) (u+n,2n+1)

跑欧拉回路,然后根据前两类边的方向就可以确定原图中边的方向。

代码很简单。但是确实比较难想到😅

我是小丑,所以写了第一种做法。

cpp 复制代码
#include<bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
using namespace std;
const int N=6e5+5;
int n,m,ok[N],vs[N],vs2[N],U[N],V[N],W[N],du[N],du2[N],cnt,tot;
pair<int,int>ans[N];
vector<int>s[N][2];
vector<int>vec;
vector<int>G[N];
vector<int>G2[N];
int get(int x,int y){
    if(y==U[x])return V[x];
    return U[x];
}
void dfs(int i,int pre,int j){
    while(s[i][j].size()&&vs[s[i][j].back()]){
        s[i][j].pop_back();
    }if(s[i][j].size()==0){
        vec.pb(pre);
        return;
    }int t=s[i][j].back();
    vs[t]=1,s[i][j].pop_back();
    cnt++,U[cnt]=get(pre,i),V[cnt]=get(t,i),vs[cnt]=1;
    G[cnt].pb(t),G[cnt].pb(pre),du2[t]++,du2[pre]++;
    dfs(V[cnt],cnt,j);
}
void dfs2(int u){
    while(G2[u].size()&&vs2[G2[u].back()])G2[u].pop_back();
    if(G2[u].size()==0)return;
    int t=G2[u].back();G2[u].pop_back();
    vs2[t]=1,ans[t]={u,get(t,u)},dfs2(get(t,u));
}
void dfs3(int u){
    if(G[u].size()){
        int l=G[u][0],r=G[u][1];
        if(V[l]==U[r]){
            ans[l]={U[l],V[l]},ans[r]={U[r],V[r]};
        }
        else if(U[l]==U[r]){
            ans[l]={V[l],U[l]},ans[r]={U[r],V[r]};
        }
        else if(V[l]==V[r]){
            ans[l]={U[l],V[l]},ans[r]={V[r],U[r]};
        }
        else{
            ans[l]={V[l],U[l]},ans[r]={V[r],U[r]};
        }if(ans[l].fi!=ans[u].fi){
            swap(ans[l].fi,ans[l].se);
            swap(ans[r].fi,ans[r].se);
        }
        dfs3(l),dfs3(r);
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin>>n>>m,cnt=m;
    for(int i=1;i<=m;i++){
        int u,v,w;cin>>u>>v>>w,w--;
        s[u][w].pb(i),s[v][w].pb(i);
        if(w==0)ok[u]^=1,ok[v]^=1;
        U[i]=u,V[i]=v,W[i]=w;
    }
    for(int i=1;i<=n;i++){
        for(int j=0;j<2;j++){
            while(1){
                while(s[i][j].size()&&vs[s[i][j].back()])s[i][j].pop_back();
                if(s[i][j].size()==0)break;
                int t=s[i][j].back();s[i][j].pop_back();
                vs[t]=1,dfs(get(t,i),t,j);
            }while(vec.size()){
                int t=vec.back();vec.pop_back();
                vs[t]=0,s[U[t]][j].pb(t),s[V[t]][j].pb(t);
            }
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=0;j<2;j++){
            while(1){
                while(s[i][j].size()&&vs[s[i][j].back()])s[i][j].pop_back();
                if(s[i][j].size()==0)break;
                int t=s[i][j].back();s[i][j].pop_back();
                vs[t]=1;int k=get(t,i);
                du[i]++,du[k]++,G2[i].pb(t),G2[k].pb(t);
            }
        }
    }
    for(int i=1;i<=n;i++)if(du[i]==1)dfs2(i);
    for(int i=1;i<=n;i++)dfs2(i);
    for(int i=1;i<=cnt;i++)if(du2[i]==0)dfs3(i);
    for(int i=1;i<=n;i++)tot+=ok[i];
    cout<<tot<<"\n";
    for(int i=1;i<=m;i++){
        if(ans[i].fi==U[i])cout<<1;
        else cout<<2;
    }
}
相关推荐
C+-C资深大佬几秒前
C++ 数字与字符串互转
java·c++·算法
知识分享小能手2 分钟前
Hadoop学习教程,从入门到精通, Hadoop 3.x 高可用集群 — 知识点详解(6)
大数据·hadoop·学习
满怀冰雪7 分钟前
第12篇-二分答案法-当答案不好求时如何反向搜索
java·算法
KaMeidebaby9 分钟前
卡梅德生物技术快报|兔单克隆抗体应用实战:禽源病原 IFA 检测全流程拆解
前端·人工智能·物联网·算法·百度
CC数学建模11 分钟前
2026年第十六届APMCM 亚太地区大学生数学建模竞赛(中文赛项)赛题A题:自来水厂水质预测与评估完整思路、代码、模型、文章,全网首发高质量分享!
python·算法·数学建模
searchforAI12 分钟前
坚持用AI做笔记,我的知识留存与学习速度大幅提升
人工智能·笔记·学习·ai·知识图谱·知识管理
Chris _data1 小时前
c#学习WPF笔记(一)
学习·c#·wpf
折哥的程序人生 · 物流技术专研8 小时前
Java面试85题图解版 · 特别篇:2026后端高频面试题复盘(算法底层逻辑+高并发架构设计全解析,附Java实战代码)
java·网络·数据库·算法·面试
AOwhisky8 小时前
Redis 学习笔记(第三期):持久化与主从复制
运维·数据库·redis·笔记·学习·云计算
问心无愧05138 小时前
ctf show web入门160 161
前端·笔记