「题解注释」CF1707C DFS Trees
题解 CF1707C【DFS Trees】 - rui_er 的博客 - 洛谷博客 (luogu.com.cn)
耗时:一个小时
代码注释:
// Problem: C. DFS Trees
// Contest: Codeforces - Codeforces Round #808 (Div. 1)
// URL: https://codeforces.com/contest/1707/problem/C
// Memory Limit: 256 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
//By: OIer rui_er
#include <bits/stdc++.h>
#define rep(x,y,z) for(int x=(y);x<=(z);x++)
#define per(x,y,z) for(int x=(y);x>=(z);x--)
#define debug printf("Running %s on line %d...\n",__FUNCTION__,__LINE__)
#define fileIO(s) do{freopen(s".in","r",stdin);freopen(s".out","w",stdout);}while(false)
using namespace std;
typedef long long ll;
const int N = 2e5+5;
int n, m, vis[N], fa[N][20], dis[N], s[N];
vector<tuple<int, int> > e;
vector<int> t[N];
template<typename T> void chkmin(T& x, T y) {if(x > y) x = y;}
template<typename T> void chkmax(T& x, T y) {if(x < y) x = y;}
struct Dsu {
int fa[N];
void init(int x) {rep(i, 1, x) fa[i] = i;}
int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);}
bool merge(int x, int y) {
int u = find(x), v = find(y);
if(u == v) return 0;
fa[u] = v;
return 1;
}
}dsu;
void kruskal() { // kruskal 找最小生成树
dsu.init(n);
rep(i, 0, m-1) {
int u = get<0>(e[i]), v = get<1>(e[i]);
if(dsu.merge(u, v)) {
vis[i] = 1; // 打标记
t[u].push_back(v); // 最小生成树上的树边
t[v].push_back(u);
}
}
}
void dfs1(int u, int f) { // 跑最小生成树,建立倍增数组
fa[u][0] = f;
dis[u] = dis[f] + 1;
rep(i, 1, 19) fa[u][i] = fa[fa[u][i-1]][i-1];
for(int v : t[u]) if(v != f) dfs1(v, u);
}
int LCA(int u, int v) {
if(dis[u] < dis[v]) swap(u, v);
per(i, 19, 0) if(dis[fa[u][i]] >= dis[v]) u = fa[u][i];
if(u == v) return u;
per(i, 19, 0) if(fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i];
return fa[u][0];
}
void dfs2(int u, int f) {
s[u] += s[f];
for(int v : t[u]) if(v != f) dfs2(v, u);
}
int main() {
scanf("%d%d", &n, &m); // n 个点,m 条边
rep(i, 0, m-1) { // 建图
int u, v;
scanf("%d%d", &u, &v);
e.emplace_back(u, v);
}
kruskal(); // 找最小生成树
dfs1(1, 0); // dfs 最小生成树
rep(i, 0, m-1) {
if(!vis[i]) {
int u = get<0>(e[i]), v = get<1>(e[i]);
int lca = LCA(u, v);
if(dis[u] > dis[v]) swap(u, v);
if(lca == u) { // 在 1 为根时已经是祖先后代关系了,那就只有链上的点不满足要求
++s[1], ++s[v];
int p = v;
per(j, 19, 0) if(dis[fa[p][j]] > dis[u]) p = fa[p][j];
--s[p];
}
else ++s[u], ++s[v]; // 只有 u, v 两点往下的点能够符合“提溜起来”使得 u, v 是祖先后代关系
}
}
dfs2(1, 0); // 从上往下下传标记
rep(i, 1, n) putchar(s[i]==m-n+1?'1':'0');
puts("");
return 0;
}
作者:yifan0305
出处:https://www.cnblogs.com/yifan0305/p/17630881.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
转载时还请标明出处哟!
朝气蓬勃 后生可畏
分类:
题解注释
Buy me a cup of coffee ☕.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】