ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Atcoder Grand Contest 025 E - Walking on a Tree(欧拉回路)

2022-08-14 16:33:36  阅读:170  来源: 互联网

标签:Atcoder Walking Contest int void fa MAXN print define


Atcoder 题面传送门

打个表发现答案等于每条边被覆盖的次数与 \(2\) 取 min 之和,考虑如何构造这个上界。

首先考虑树是以 \(1\) 为中心的菊花图,且任意 \(A_i,B_i\ne 1\) 的做法:我们考虑在 \(A_i,B_i\) 之间连边。那么发现限制等价于,对每条边定向使得每个度 \(\ge 2\) 的点至少有一个出边和一个出边,这是经典欧拉回路问题,只需要让每个点入度和出度差 \(\le 1\) 即可满足条件,直接建虚点连向所有奇度点,然后对每个连通块做欧拉回路即可。

实际上这个做法对于每个点 \(x\) 恰有偶数个 \(i\) 满足 \(A_i=x\) 或 \(B_i=x\) 的情况也是成立的。因为这意味着我们在 \(A_i,B_i\) 之间连边后,连出来的图中每个连通块都是欧拉图。那么我们考察每条“存在至少一个路径 \(A_i\to B_i\) 经过”的边 \((u,v)\),我们假设断开这条边后树形成的两个点集为 \(S,T\),那么欧拉回路的一个性质是对于一组满足 \(S\cap T=\varnothing,S\cup T=V\) 的 \(S,T\),\(S\to T\) 的边数与 \(T\to S\) 的边数相同,这容易通过欧拉回路的性质说明,这也就意味着至少存在一条路径满足其经过 \(u,v\) 时是 \(u\to v\),也至少存在一条 \(v\to u\) 的路径。也就自然构造到了上界。

考虑如果出现奇度点怎么办,我们考虑从上到下 DFS,对于一个点 \(x\) 的某个儿子 \(y\),如果 \(y\) 目前度数是奇数,那么加入路径 \((x,y)\),容易证明这样构造的正确性。

时间复杂度 \(n\log n\)。

#include <bits/stdc++.h>
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/hash_policy.hpp>
// #include <ext/pb_ds/priority_queue.hpp>
using namespace std;
// using namespace __gnu_pbds;
#define fi first
#define se second
#define fill0(a) memset(a, 0, sizeof(a))
#define fill1(a) memset(a, -1, sizeof(a))
#define fillbig(a) memset(a, 63, sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
#define mt make_tuple
#ifdef LOCAL
#define eprintf(...) fprintf(stderr, __VA_ARGS__)
#else
#define eprintf(...) 1064
#endif
template<typename T1, typename T2> void chkmin(T1 &x, T2 y) {if (x > y) x = y;}
template<typename T1, typename T2> void chkmax(T1 &x, T2 y) {if (x < y) x = y;}
typedef pair<int, int> pii;
typedef long long ll;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef long double ld;
#ifdef FASTIO
#define FILE_SIZE 1 << 23
char rbuf[FILE_SIZE], *p1 = rbuf, *p2 = rbuf, wbuf[FILE_SIZE], *p3 = wbuf;
#ifdef LOCAL
inline char getc() {return getchar();}
inline void putc(char c) {putchar(c);}
#else
inline char getc() {return p1 == p2 && (p2 = (p1 = rbuf) + fread(rbuf, 1, FILE_SIZE, stdin), p1 == p2) ? -1 : *p1++;}
inline void putc(char x) {*p3++ = x;}
#endif
template<typename T> void read(T &x) {
	x = 0; char c = getc(); T neg = 0;
	while (!isdigit(c)) neg |= (c == '-'), c = getc();
	while (isdigit(c)) x = x * 10 + (c - '0'), c = getc();
	if (neg) x = -x;
}
template<typename T> void recursive_print(T x) {
	if (!x) return;
	recursive_print(x / 10); putc(x % 10 ^ 48);
}
template<typename T> void print(T x) {
	if (!x) putc('0'); if (x < 0) putc('-'), x = -x;
	recursive_print(x);
}
template<typename T> void print(T x, char c) {print(x); putc(c);}
void readstr(char *s) {
	char c = getc();
	while (c <= 32 || c >= 127) c = getc();
	while (c > 32 && c < 127) s[0] = c, s++, c = getc();
	(*s) = 0;
}
void printstr(string s) {for (int i = 0; i < s.size(); i++) putc(s[i]);}
void printstr(char *s) {
	int len = strlen(s);
	for (int i = 0; i < len; i++) putc(s[i]);
}
void print_final() {fwrite(wbuf, 1, p3 - wbuf, stdout);}
#endif
const int MAXN = 1e5;
const int LOG_N = 18;
const int MAXE = 1e6;
int n, m, A[MAXN + 5], B[MAXN + 5]; vector<int> g[MAXN + 5];
int fa[MAXN + 5][LOG_N + 2], dep[MAXN + 5];
void dfs0(int x, int f) {
	fa[x][0] = f;
	for (int y : g[x]) {
		if (y == f) continue; dep[y] = dep[x] + 1;
		dfs0(y, x);
	}
}
int getlca(int x, int y) {
	if (dep[x] < dep[y]) swap(x, y);
	for (int i = LOG_N; ~i; i--) if (dep[x] - (1 << i) >= dep[y]) x = fa[x][i];
	if (x == y) return x;
	for (int i = LOG_N; ~i; i--) if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
	return fa[x][0];
}
int mark[MAXN + 5], deg[MAXN + 5], hd[MAXN + 5], to[MAXE + 5], nxt[MAXE + 5], ec = 1;
void adde(int u, int v) {to[++ec] = v; nxt[ec] = hd[u]; hd[u] = ec;}
void dfs1(int x, int f) {
	for (int y : g[x]) {
		if (y == f) continue; dfs1(y, x); mark[x] += mark[y];
		if (deg[y]) deg[x] ^= 1, deg[y] ^= 1, adde(x, y), adde(y, x);
	}
}
int dir[MAXE + 5], vis[MAXN + 5];
void dfs2(int x) {
	vis[x] = 1;
	for (int &e = hd[x]; e; e = nxt[e]) if (dir[e >> 1] == -1)
		dir[e >> 1] = e & 1, dfs2(to[e]);
}
int main() {
#ifdef LOCAL
	freopen("in.txt", "r", stdin);
	freopen("out.txt", "w", stdout);
#else
	freopen("path.in", "r", stdin);
	freopen("path.out", "w", stdout);
#endif
	scanf("%d%d", &n, &m);
	for (int i = 1, u, v; i < n; i++) scanf("%d%d", &u, &v), g[u].pb(v), g[v].pb(u); dfs0(1, 0);
	for (int i = 1; i <= LOG_N; i++) for (int j = 1; j <= n; j++) fa[j][i] = fa[fa[j][i - 1]][i - 1];
	for (int i = 1; i <= m; i++) {
		scanf("%d%d", &A[i], &B[i]); int lc = getlca(A[i], B[i]);
		mark[A[i]]++; mark[B[i]]++; mark[lc] -= 2; adde(A[i], B[i]); adde(B[i], A[i]);
		deg[A[i]] ^= 1; deg[B[i]] ^= 1;
	}
	dfs1(1, 0); memset(dir, -1, sizeof(dir));
	for (int i = 1; i <= n; i++) if (!vis[i]) dfs2(i);
	int res = 0; for (int i = 1; i <= n; i++) res += min(mark[i], 2);
	printf("%d\n", res);
	for (int i = 1; i <= m; i++) {
		if (dir[i]) printf("%d %d\n", A[i], B[i]);
		else printf("%d %d\n", B[i], A[i]);
	}
	return 0;
}

标签:Atcoder,Walking,Contest,int,void,fa,MAXN,print,define
来源: https://www.cnblogs.com/ET2006/p/agc025E.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有