CF1994 F. Stardew Valley [欧拉回路+树上差分]

传送门

[前题提要]:自模板题以后,很少遇到欧拉回路的题目,正好这道题结合了多种经典算法,故写一篇题解记录一下

读完题面,因为需要经过所有1边,所以很显然会想到应该将所有的1边拿出来建一个新图,然后在新图上添加0边,使得新图是一个欧拉图.

让我们来回忆一下什么是欧拉图.对于无向图,其可以构造出欧拉回路的充要条件是所有点的度数都是偶数.

所以问题就变成了对于1图中度数为奇数的点,我们通过对其添加0边使得其的度数变为偶数.此时应该不难想到应该将那些度数为奇数的点拿出来考虑.并且应该会想到一个朴素的想法,我们给两个度数为奇数的点连一条边,他们不就同时变成偶数了吗.诶,此时应该还会诞生一个新的问题就是,如果两个度数为奇数的点之间不存在一条直连0边,那么我们该怎么办呢.我们如果找到一条路径是以这两个点为端点的0边路径,我们将其加入我们的1图中,会发生什么呢,我们会发现对于路径上的点我们这条路径并不会改变其奇偶性,而对于这两个点,我们改变了其奇偶性.那么问题就简单了,我们只要找到一些以上述点为端点的路径即可.但是此时又带来了一个新的问题,就是对于两条不同的需要加入的路径,他们可能存在一些边是重复的.肯定不能反复加入边.但是仔细想一想,我们之前加入一条路径是为了什么,是因为这样可以使我们中间点的度数奇偶性不改变,不然我们直接选两个要改变的点的直连边就行了,所以我们此时再想一下,对于重复边,如果他被选择的次数是偶数的话,那么我们不选择这条边,其点的奇偶性依旧没有变化.也就是对于覆盖次数为偶数的边,我们完全可以不选择加入该边,只对于覆盖次数为奇数的边我们才选择加入.附一张解释图:

在这里插入图片描述
对于(1,6),(5,7)来说,我们想改变他们,直接选择<1,2>,<2,5>,<4,6>,<4,7>即可.

所以的问题就变成了对于两个点,怎么找到一条连边.还要保证快速找到一条合法路径.注意到我们只需要找到任意一条路径即可.那么我们不难想到可以生成树.考虑对于0边所组成的图,我们对其进行生成树.那么我们最终会得到一个生成树森林.为什么是森林,因为原来的0边所组成的图并不一定是连通的.那么对于不同生成树之间是独立的,因为他们之间必然是不可能连边的.所以我们只要单独的去考虑每一棵生成树即可.那么不难会发现,对于一棵树,如果奇数度数节点的个数是奇数个,那么我们必然不可能完成目标,为什么这么说,因为我们不妨先每次选择两个没有被选择过的点,这样最后会剩下一个需要选择的点,此时我们会发现无论怎么选择,永远都会有一个点是奇数度数的节点,这个过程就和翻面(或者是点关灯)问题有点类似.反之,如果个数是偶数个,我们永远都可以直接选择两个没有被选过的点,然后加入以这两个点为端点的路径,使其满足条件

那么最后我们只需要跑一下欧拉回路的板子即可.对于如何求出一个合法欧拉图的欧拉回路,此处就不在赘述了.


下面是具体的代码部分:

 //It is guaranteed that you can reach any house from any other by walking on the roads with NPCs only.
//品了好久才明白,原来这句话保证了只保留1边依旧是一个联通图,又需要走全部1边,所以最终的欧拉回路是包括n个点的
//我本来还以为只是保证所有1边相连是一个联通图(也就是有些点的联通块全是0边).....
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls (rt<<1)
#define rs (rt<<1|1)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define pd __gnu_pbds
inline ll read() {ll x=0,w=1;char ch=getchar();for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';return x*w;
}
inline void print(__int128 x){if(x<0) {putchar('-');x=-x;}if(x>9) print(x/10);putchar(x%10+'0');
}
#define maxn 1000010
const double eps=1e-8;
#define	int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
vector<int>edge0[maxn];vector<pair<int,int> >edge1;
int in[maxn];int fa[maxn];
vector<int>tree[maxn];
vector<int>node[maxn];
int find(int x) {if(fa[x]==x) return x;else return fa[x]=find(fa[x]);
}int FA[maxn],max_son[maxn],Size[maxn],dep[maxn];
void dfs1(int u,int per_u) {Size[u]=1;for(int i=0;i<tree[u].size();i++) {int v=tree[u][i];if(v==per_u) continue;dep[v]=dep[u]+1;dfs1(v,u);FA[v]=u;Size[u]+=Size[v];if(Size[v]>Size[max_son[u]]) {max_son[u]=v;}}
}
int top[maxn];
void dfs2(int u,int t) {top[u]=t;if(!max_son[u]) return ;dfs2(max_son[u],t);for(int i=0;i<tree[u].size();i++) {int v=tree[u][i];if(v==FA[u]||v==max_son[u]) continue;dfs2(v,v);}
}
int LCA(int u,int v) {while(top[u]!=top[v]) {if(dep[top[u]]<dep[top[v]]) swap(u,v);u=FA[top[u]];}if(dep[u]>dep[v]) swap(u,v);return u;
}
int sum[maxn];
void dfs(int u,int pre_u) {for(auto v:tree[u]) {if(v==pre_u) continue;dfs(v,u);sum[u]+=sum[v];if(sum[v]&1) {edge1.push_back({u,v});}}
}vector<pair<int,int> >ng[maxn];
vector<int>path;
bool used[maxn];
void dfs_euler(int u){while(!ng[u].empty()){auto [j,id]=ng[u].back();ng[u].pop_back();if(used[id]) continue;used[id]=true;dfs_euler(j);}path.push_back(u);
}int main() {int T=read();while(T--) {int n=read();int m=read();for(int i=1;i<=m;i++) {int u=read();int v=read();int c=read();if(c) {edge1.push_back({u,v});in[u]++;in[v]++;}else {edge0[u].push_back(v);edge0[v].push_back(u);}}vector<int>v;for(int i=1;i<=n;i++) {if(in[i]&1) {v.push_back(i);}}for(int i=1;i<=n;i++) {fa[i]=i;}for(int i=1;i<=n;i++) {for(auto v:edge0[i]) {if(find(i)==find(v)) {continue;}fa[find(i)]=find(v);tree[i].push_back(v);tree[v].push_back(i);}}vector<int>ID;for(int i=1;i<=n;i++) {node[find(i)].push_back(i);if(find(i)==i) {ID.push_back(i);}}int flag=0;for(auto id:ID) {dfs1(id,0);dfs2(id,id);vector<int>temp;for(auto i:node[id]) {if(in[i]&1) {temp.push_back(i);}}if(temp.size()&1) {flag=1;break;}for(int i=1;i<temp.size();i+=2) {sum[temp[i-1]]++;sum[temp[i]]++;sum[LCA(temp[i-1],temp[i])]-=2;}dfs(id,0);}if(flag) {printf("NO\n");}else {printf("YES\n");int st=-1;for(int i=0;i<edge1.size();i++) {auto [a,b]=edge1[i];if(st==-1) st=a;ng[a].push_back({b,i});ng[b].push_back({a,i});}dfs_euler(st);printf("%d\n",path.size()-1);reverse(path.begin(),path.end());for(auto i:path) {printf("%d ",i);}printf("\n");	}//clearedge1.clear();path.clear();for(int i=0;i<=n;i++) {edge0[i].clear();node[i].clear();tree[i].clear();in[i]=fa[i]=FA[i]=max_son[i]=Size[i]=dep[i]=0;ng[i].clear();sum[i]=0;top[i]=0;}for(int i=0;i<=m;i++) {used[i]=0;}}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/150081.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【秋招笔试题】多多的平均值

解法&#xff1a;抽掉的两个数字之和为2倍的平均数&#xff0c;那么判断一下2倍的平均数是不是整数。然后在搞一个哈希表存取过的值即可。 package com.sky;import java.util.*;public class Test1 {public static void main(String[] args) {Scanner scanner new Scanner(Sy…

计算机研一规划2024/9/22

系列文章目录 文章目录 系列文章目录前言一、两条腿走路二、编程语言能力提升1.廖雪峰的python课2.Leetcode&#xff08;数据结构题&#xff09; 三、机器学习能力提升1.统计学习方法 李航2.kaggle竞赛 四、神经网络能力提升1.神经网络与深度学习 邱锡鹏2.一套自己的万金油模板…

openai最新o1上线(2024年09月12日)

gpt-4o-2024-08-06输出文本价格 10美元/M o1-preview输出价格 60美元/M https://lmarena.ai/?leaderboard 数字9.11和9.8谁大些 人工智能学习网站 https://chat.xutongbao.top/

Vue(16)——Vue3.3新特性

defineOptions 在 Vue 3.3 之前&#xff0c;如果需要在 <script setup> 中设置组件名&#xff0c;通常需要在额外的 <script> 标签中使用 Options API 进行配置。defineOptions 是 Vue 3.3 版本中引入的一个宏&#xff08;macro&#xff09;&#xff0c;它主要用于…

C++ bitset(位图)的介绍和使用

文章目录 一、bitset的介绍1. 位图的引入2. 位图的概念3. 位图的应用场景 二、bitset的使用1. 定义方式2. 成员函数3. 运算符重载 一、bitset的介绍 1. 位图的引入 面试题 给40亿个不重复的无符号整数&#xff0c;没排过序。给一个无符号整数&#xff0c;如何快速判断一个数是…

2024年蓝牙网关市场热门产品选购宝典

在本文中&#xff0c;我们将探讨不同类型的蓝牙网关及其分类&#xff0c;并提供一份指南&#xff0c;帮助您筛选出最适合的物联网网关。 室内蓝牙网关 室内网关通常用于智能建筑解决方案&#xff0c;如智能家居、零售店、购物中心和办公室。 这些网关的覆盖范围较短&#xff…

人工智能代表——无人驾驶:萝卜快跑

人工智能如何改变我们的出行&#xff1a;以“萝卜快跑”无人驾驶为例 随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;正以前所未有的方式渗透并改变着我们的日常生活&#xff0c;其中出行方式的变革尤为显著。在众多AI驱动的出行创新中&#xff0c;“萝卜…

【hot100-java】【缺失的第一个正数】

R9-普通数组篇 class Solution {public int firstMissingPositive(int[] nums) {int nnums.length;for (int i0;i<n;i){while(nums[i]>0&&nums[i]<n&&nums[nums[i]-1]!nums[i]){//交换nums[i]和nums[nums[i]-1]int temp nums[nums[i]-1];nums[nums[i]…

C语言课程设计题目(24个选题)

C语言课程设计题目 一、设计要求与设计报告二、检查要求三、打分标准四、提交时间五、选题要求题目列表题目一&#xff1a;职工信息管理系统设计题目二&#xff1a;图书信息管理系统设计题目三&#xff1a;图书管理系统设计题目四&#xff1a;实验设备管理系统设计题目五&#…

回答网友的一个SQL问题

网友问&#xff1a; CODE NAME 1 A 1 B 如何得到下面的值&#xff0c;该如何写SQL CODE NAME 1 AB 1 AB 俺的回答&#xff1a; declare t table(code varchar(50),name varchar(50)) insert into t(code,name) select 1,A union select…

python脚本程序怎么写更优雅?argparse模块巧妙应用

前言 命令行程序&#xff0c;也称CLI程序&#xff0c;另一个直观的名字是脚本程序&#xff0c;简称脚本&#xff0c;由于没有图形用户界面&#xff08;GUI&#xff09;&#xff0c;所以脚本程序常见的交互方式有3种&#xff1a; 1、脚本程序中读取环境变量&#xff0c;比如env…

Spring Security学习

系列文章目录 第一章 基础知识、数据类型学习 第二章 万年历项目 第三章 代码逻辑训练习题 第四章 方法、数组学习 第五章 图书管理系统项目 第六章 面向对象编程&#xff1a;封装、继承、多态学习 第七章 封装继承多态习题 第八章 常用类、包装类、异常处理机制学习 第九章 集…

【深度学习】深度卷积神经网络(AlexNet)

在 LeNet 提出后&#xff0c;卷积神经网络在计算机视觉和机器学习领域中很有名气&#xff0c;但并未起到主导作用。 这是因为 LeNet 在更大、更真实的数据集上训练的性能和可行性还有待研究。 事实上&#xff0c;在 20 世纪 90 年代到 2012 年之间的大部分时间里&#xff0c;…

电线杆上电气组件检测系统源码分享

电线杆上电气组件检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Comp…

视频怎么制作成二维码?视频轻松生成二维码的3步操作

现在很多人为了能够更快捷的实现视频内容的分享&#xff0c;会通过将视频生成二维码的方式&#xff0c;让其他人可以通过扫描二维码来查看视频内容。这种方式不需要用户存储视频&#xff0c;扫码就能够在设备上查看视频&#xff0c;有利于提升查看视频的便捷性&#xff0c;可以…

【秋招笔试题】多多排序

解法&#xff1a;简单语法题 package com.sky;import java.util.*;public class Test1 {public static void main(String[] args) {Scanner sc new Scanner(System.in);int N sc.nextInt();int M sc.nextInt();List<String> words new ArrayList<>(N);for (in…

关于TrustedInstaller权限

前言 我们在在删除某些文件时会发现权限不够的情况&#xff0c;那是因为自从 Windows Vista 以来&#xff0c;为了提升安全性&#xff0c;微软对于权限的把控越来越紧。为了对抗恶意软件随意修改系统文件&#xff0c;Trustedinstaller 应运而生。 各权限之间的关系 普通人:Us…

C++STL--------string

文章目录 一、STL介绍二、string1、constructor构造函数2、operator[]方括号运算符重载3、iterator迭代器4、reverse_iterator反向迭代器5、size和length6、capacity7、clear8、shrink_to_fit9、at10、push_back11、append 二、auto类型(C11)1、使用2、真正的价值 三、范围for(…

python全栈学习记录(十八)re、os和sys、subprocess

re、os和sys、subprocess 文章目录 re、os和sys、subprocess一、re1.正则字符2.正则表达式的使用3.group的使用4.贪婪匹配与惰性匹配5.其他注意事项 二、os和sys1.os2.sys 三、subprocess 一、re python中的re模块用来使用正则表达式&#xff0c;正则就是用一系列具有特殊含义…

2024 年最新 Protobuf 结构化数据序列化和反序列化详细教程

Protobuf 序列化概述 Protobuf&#xff08;Protocol Buffers&#xff09;是由Google开发的一种语言中立、平台中立、可扩展的序列化结构数据的方法。它用于在不同系统之间高效地交换数据。Protobuf使用定义文件&#xff08;.proto&#xff09;来描述数据结构&#xff0c;并通过…