CodeForces 1268E Happy Cactus
考虑一些简单的情况,比如树。
设 为当前 能通过边权递增的路径到达的点数(包括它自己)。
为了让两个点对在边权递增路径的边权最小的那条边被统计,我们倒序枚举边。当枚举到 时,我们有 。
这是因为 能通过 这条边到达全部 能到达的点,并且 的边权一定是最小的。 同理。并且 此前不连通,所以能到达的点不会重复。
现在给定的是一棵仙人掌,我们可以照搬树的做法,但是出问题了。原因在于,我们枚举到边 时, 可能已经在环上有唯一一条简单路径了。
但是注意到,算重仅当环上存在点 使得 的路径边权递增且 的路径边权递增。那么此时 的路径上边权先增后减。
设环上边权最大的那条边为 。此时我们会算重 能到达的环外的点和点 。
记 为枚举完边权为 的边 后 能到达的点数。注意我们只需要用到环上最大边的 ,所以当 是环上最大边时,我们计算 。当枚举到环上最小边 时,设这个环的最大边权为 。如果这个环的边权先增后减,我们有 。
我们剩下的任务是找环。因为给定的是仙人掌,所以环的边不会相交,我们直接建出 dfs 树,每一条返祖边就对应一个环。
时间复杂度 。
code
// Problem: E. Happy Cactus // Contest: Codeforces - Codeforces Round 609 (Div. 1) // URL: https://codeforces.com/problemset/problem/1268/E // Memory Limit: 256 MB // Time Limit: 3000 ms // // Powered by CP Editor (https://cpeditor.org) #include <bits/stdc++.h> #define pb emplace_back #define fst first #define scd second #define mems(a, x) memset((a), (x), sizeof(a)) using namespace std; typedef long long ll; typedef unsigned long long ull; typedef double db; typedef long double ldb; typedef pair<int, int> pii; const int maxn = 500100; int n, m, dep[maxn], stk[maxn], top, col[maxn], cnt, f[maxn], g[maxn]; int mne[maxn], mxe[maxn]; bool vis[maxn], mk[maxn]; pii E[maxn]; vector<pii> G[maxn]; vector<int> cir[maxn]; void dfs(int u, int fa) { vis[u] = 1; for (pii p : G[u]) { int v = p.fst, id = p.scd; if (v == fa) { continue; } if (vis[v]) { if (dep[v] < dep[u]) { ++cnt; for (int i = 0; i < dep[u] - dep[v]; ++i) { int w = stk[top - i]; col[w] = cnt; cir[cnt].pb(w); } col[id] = cnt; cir[cnt].pb(id); reverse(cir[cnt].begin(), cir[cnt].end()); } continue; } dep[v] = dep[u] + 1; stk[++top] = id; dfs(v, u); --top; } } void solve() { scanf("%d%d", &n, &m); for (int i = 1; i <= m; ++i) { scanf("%d%d", &E[i].fst, &E[i].scd); G[E[i].fst].pb(E[i].scd, i); G[E[i].scd].pb(E[i].fst, i); } dfs(1, -1); for (int i = 1; i <= cnt; ++i) { int mx = max_element(cir[i].begin(), cir[i].end()) - cir[i].begin(); vector<int> vc; mxe[i] = cir[i][mx]; for (int j = mx + 1; j < (int)cir[i].size(); ++j) { vc.pb(cir[i][j]); } for (int j = 0; j < mx; ++j) { vc.pb(cir[i][j]); } int mn = min_element(vc.begin(), vc.end()) - vc.begin(); mne[i] = vc[mn]; bool flag = 1; for (int j = 0; j < mn; ++j) { flag &= (vc[j] > vc[j + 1]); } for (int j = mn; j + 1 < (int)vc.size(); ++j) { flag &= (vc[j] < vc[j + 1]); } if (flag) { mk[i] = 1; } } for (int i = 1; i <= n; ++i) { f[i] = 1; } for (int i = m; i; --i) { int u = E[i].fst, v = E[i].scd; f[u] = f[v] = f[u] + f[v] - (mk[col[i]] && i == mne[col[i]] ? g[mxe[col[i]]] : 0); if (mk[col[i]] && i == mxe[col[i]]) { g[i] = f[u]; } } for (int i = 1; i <= n; ++i) { printf("%d ", f[i] - 1); } } int main() { int T = 1; // scanf("%d", &T); while (T--) { solve(); } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
2022-07-28 洛谷 P4899 [IOI2018] werewolf 狼人
2022-07-28 CodeForces 1628E Groceries in Meteor Town
2022-07-28 CodeForces 1416D Graph and Queries
2022-07-28 Kruskal 重构树学习笔记
2022-07-28 CodeForces 1706E Qpwoeirut and Vertices