ICode9

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

CF 793 div2 E 题解

2022-06-09 21:01:11  阅读:243  来源: 互联网

标签:fx 793 int 题解 CF mxn fa fy dep


793div2 E

可上 CF 看本题解

建模不多说,你会把排列拆成若干个轮换,然后对于长为 \(k\) 的轮换,会且仅会用 \(k-1\) 次交换(因为题目保证用的次数是最少的)。

把这些交换抓出来建图,会得到一个森林,你需要给每条边定向,使得每棵树的拓扑序都可以和原轮换循环同构。

考虑如果满足一个 \(i\to p_i\) 的置换,那么你操作的顺序一定是在树上从 \(i\) 开始走然后走到 \(p_i\),这样的路径是唯一的。设经过了 \(m\) 条边分别是 \(e_1,e_2,\cdots,e_m\),这 \(m\) 条边会有严格拓扑序 \(\mathrm{opt}_{e_1}<\mathrm{opt}_{e_2}<\cdots<\mathrm{opt}_{e_m}\)。

而这 \(m\) 条边有这些拓扑序恰是满足 \(i\to p_i\) 置换的充要条件。

充分:按这个拓扑序 \(i\) 可以走到 \(p_i\)。

必要:树上路径唯一。

所以对于每个 \(i\to p_i\),在树上抓出这些路径然后加上有向边,最后拓扑排序即可。

这样做是对的,因为一条边是交换两个数字,最多只会影响两个置换,所以会且恰好会被两条路径覆盖。

总时间复杂度是 \(O(n)\) 的。

关于怎么抓出路径,无根转有根后暴力跳 \(\mathrm{lca}\) 即可。

贴个代码以免有人说我在口胡

// Problem: E. Unordered Swaps
// From: Codeforces - Codeforces Round #793 (Div. 2)
// URL: https://codeforces.com/contest/1682/problem/E
// Time: 2022-05-22 22:36
// Author: lingfunny

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int mxn = 2e5+10;

int n, m, a[mxn], p[mxn], dep[mxn], in[mxn];

typedef pair<int, int> edge;
vector <edge> G[mxn];
edge fa[mxn];
vector <int> nodes, g[mxn];

inline void adde(int u, int v) { ++in[v]; g[u].push_back(v); }

void dfs(int u, int f) {
	dep[u] = dep[f] + 1; nodes.push_back(u);
	for(auto [id, v]: G[u]) if(v != f) fa[v] = {id, u}, dfs(v, u);
}

inline void solve(int u) {
	vector <int>().swap(nodes);
	dfs(u, 0);
	for(int x: nodes) {
		int y = p[x];	// x -> y
		vector <int> fx, fy;
		while(dep[x] > dep[y]) fx.push_back(fa[x].first), x = fa[x].second;
		while(dep[y] > dep[x]) fy.push_back(fa[y].first), y = fa[y].second;
		while(x != y) {
			fx.push_back(fa[x].first), x = fa[x].second;
			fy.push_back(fa[y].first), y = fa[y].second;
		}
		reverse(fy.begin(), fy.end());
		fx.insert(fx.end(), fy.begin(), fy.end());
		for(int i = 1; i < (int)fx.size(); ++i)
		adde(fx[i-1], fx[i]);
	}
}

signed main() {
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; ++i) scanf("%d", p+i);
	for(int i = 1; i <= m; ++i) {
		int x, y; scanf("%d%d", &x, &y);
		G[x].push_back({i, y});
		G[y].push_back({i, x});
	}
	for(int i = 1; i <= n; ++i) if(!dep[i]) solve(i);
	queue <int> q;
	for(int i = 1; i <= m; ++i) if(!in[i]) q.push(i);
	while(q.size()) {
		int u = q.front(); q.pop();
		printf("%d ", u);
		for(int v: g[u]) if(--in[v] == 0) q.push(v);
	}
	return 0;
}

标签:fx,793,int,题解,CF,mxn,fa,fy,dep
来源: https://www.cnblogs.com/lingfunny/p/16361143.html

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

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

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

ICode9版权所有