首页 > 其他分享 >CF1268E Happy Cactus 题解

CF1268E Happy Cactus 题解

时间:2024-09-29 15:38:44浏览次数:9  
标签:emplace int 题解 back kMaxN ed Cactus CF1268E size

Description

给定一张仙人掌图,第 \(i\) 条边连接 \(u,v\),边权为 \(i\)

定义路径为 "Happy Path" 当且仅当其满足沿途边权递增。

定义点对 \((u,v)\) Happy 当且仅当存在一条 Happy Path 以 \(u\) 为起点,\(v\) 为终点。

对于 \(u=1,2...n\),求满足 \((u,v)\) Happy 的 \(v\) 的数量。

\(n,m\le 5\times 10^5\)。

Solution

先考虑树的情况怎么做。

由于这里建圆方树跑 dp 非常复杂,考虑按照编号从大到小加边。

设 \(f_i\) 表示 \(i\) 走已经加入的边能到多少个点。那么假设加入了 \((u,v)\),因为 \((u,v)\) 是当前边权最小的边,所以 \(u\) 和 \(v\) 跨过这条边后可以随便走,即让 \(f_u=f_v=f_u+f_v\)。

对于一般仙人掌的情况,直接照搬上面那个做法会出现一个问题,就是 \((u,v)\) 在加入这条边之前就已经存在共同能够到达的点了,会算重。

注意到这是个仙人掌,所以如果算重,就一定要满足 \((u,v)\) 是其所在环的最小边,且 \(u,v\) 分别能够到达所在环的最大边 \((u_0,v_0)\),这时 \(u\) 和 \(v\) 同时能到达 \(u_0,v_0\) 和通过 \((u_0,v_0)\) 能到的所有点。

算重的部分在加入 \((u_0,v_0)\) 的时候记录 \(f_{u_0}+f_{v_0}\) 即可,所有环可以在 dfs 树上求出。

时间复杂度:\(O(n+m)\)。

Code

#include <bits/stdc++.h>

// #define int int64_t

const int kMaxN = 5e5 + 5;

int n, m;
int u[kMaxN], v[kMaxN], dep[kMaxN], p[kMaxN], mat[kMaxN];
int f[kMaxN], g[kMaxN];
std::vector<int> G[kMaxN];

void dfs(int u, int pid) {
  p[u] = pid;
  for (auto id : G[u]) {
    int v = ::u[id] ^ ::v[id] ^ u;
    if (!dep[v]) {
      dep[v] = dep[u] + 1, dfs(v, id);
    } else if (dep[v] > dep[u]) {
      std::vector<int> ver, ed;
      for (int i = v; i != u; i = ::u[p[i]] ^ ::v[p[i]] ^ i)
        ver.emplace_back(i), ed.emplace_back(p[i]);
      ver.emplace_back(u), ver.emplace_back(v), ed.emplace_back(id);
      int mx = std::max_element(ed.begin(), ed.end()) - ed.begin(), mi = std::min_element(ed.begin(), ed.end()) - ed.begin();
      if ((int)ed.size() == 2) {
        mat[ed[mi]] = ed[mx];
        continue;
      }
      bool fl = 1;
      for (int i = (mx + 1) % ed.size(); i != mi; i = (i + 1) % ed.size()) {
        fl &= (ed[i] < ed[(i + (int)ed.size() - 1) % ed.size()]);
      }
      for (int i = (mx + (int)ed.size() - 1) % ed.size(); i != mi; i = (i + (int)ed.size() - 1) % ed.size()) {
        fl &= (ed[i] < ed[(i + 1) % ed.size()]);
      }
      if (fl) mat[ed[mi]] = ed[mx];
    }
  }
}

void dickdreamer() {
  std::cin >> n >> m;
  for (int i = 1; i <= m; ++i) {
    std::cin >> u[i] >> v[i];
    G[u[i]].emplace_back(i), G[v[i]].emplace_back(i);
  }
  dep[1] = 1, dfs(1, 0);
  std::fill_n(f + 1, n, 1);
  for (int i = m; i; --i) {
    g[i] = f[u[i]] = f[v[i]] = f[u[i]] + f[v[i]] - g[mat[i]];
  }
  for (int i = 1; i <= n; ++i) std::cout << f[i] - 1 << ' ';
}

int32_t main() {
#ifdef ORZXKR
  freopen("in.txt", "r", stdin);
  freopen("out.txt", "w", stdout);
#endif
  std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
  int T = 1;
  // std::cin >> T;
  while (T--) dickdreamer();
  // std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
  return 0;
}

标签:emplace,int,题解,back,kMaxN,ed,Cactus,CF1268E,size
From: https://www.cnblogs.com/Scarab/p/18440040

相关文章

  • CF2019D. Speedbreaker 题解
    介绍一种另解,以下称“征服”为“拓展”。对于这些需要拓展,且拓展的时间有上界的题,我们通常都会有一个trick。那就是对于一个点\(x\),用它可以拓展到的点\(y\)的时间上界把\(x\)的时间上界继续缩小。用到这种trick的题有P9755[CSP-S2023]种树、[ABC304Ex]ConstrainedTop......
  • CF1648D Serious Business题解
    题目链接关键:DP状态的设计\(dp[i]\)表示走到\((2,i)\)的最小价值。转移分类讨论只用一个区间\(i\)从\([li,x]\)选择位置向下拐\(dp[i]=max_{li\lek\lex}(sum[1][k]+sum[2][x]-sum[2][k-1]+v[i])\)使用别的区间显然转移点小于\(li\),不然用一个区间即可。\(dp[i]=max_......
  • Codeforces Round 975 (Div. 2) A~F 题解(Div.1 A~D)
    CodeforcesRound975(Div.2)A~F题解(Div.1A~D)也是补完整场了。A.MaxPlusSize枚举最大值的位置,使长度最长,更新答案。B.AllPairsSegments每个线段内部的点的答案都是一样的,在处理一下线段两边边界的点。被包含次数就是左边\(\times\)右边。用\(map\)记录答案......
  • pbootcms出现重复的两篇文章问题解决(实际只发布一篇)
    当遇到PBootCMS后台列表中只有一篇文章,但在前端却显示了两条的情况时,问题很可能出在数据库中的 ay_content_ext 表中存在两条重复的关联数据。以下是详细的解决方案步骤:解决方案步骤确定文章ID:在后台找到该文章的ID,假设ID为13。打开数据库工具:使用Navicat......
  • ABC373F 题解
    容易发现这是一个完全背包问题,我们设状态\(f_{i,j}\)表示前\(i\)个物品使用了\(j\)个容量的最大价值。容易写出转移方程式:\(f_{i,j}=\max\limits_{k=0}^{\lfloor\frac{j}{w}\rfloor}f_{i-1,j-kw}+kv-k^2\)直接dp是\(O(n^3)\)。考虑对这个dp进行优化。上面的方程容......
  • 题解:P9947 [USACO20JAN] Photoshoot B
    P9947[USACO20JAN]PhotoshootB题解纯模拟!在\(a_{1}\)算出来之后,我们就可以通过\(b\)数组可以求出以后\(a\)数组的所有元素。要判断是否为排列,我们可以使用一个\(vis\)做桶,为了保证字典序最小,我们可以从\(1\)开始枚举,每次枚举前要清空一下\(vis\)数组,最后使用......
  • 题解:Luogu CF548A Mike and Fax
    CF548AMikeandFax题解题面翻译给定一个字符串和一个整数\(k\),问是不是恰好存在\(k\)个子字符串是回文串,并且所有子字符串的长度一样长。题目上说有\(k\)个子字符串,我们就可以把字符串分成\(k\)份,如果分不成\(k\)份(也就是说长度不是\(k\)的倍数)的话,直接输出NO。......
  • 【C语言】手把手带你拿捏指针(完)(指针笔试、面试题解析)
    文章目录一、sizeof和strlen的对⽐1.sizeof2.strlen3.sizeof与strlen对比二、数组和指针笔试解析1.一维数组2.字符、字符串数组和字符指针代码1代码2代码3代码4代码5代码63.二维数组4.总结三、指针运算笔试题解析代码1代码2代码3代码4代码5代码6一、sizeof和strl......
  • VS2008 应用程序配置不正确,未能启动该应用程序。重新安装程序可以修复此问题解决方法
    有时候我们把自己编译好的exe直接拷贝到别的电脑上使用时,如果那台电脑没装vs,一般程序无法运行提示:应用程序配置不正确,未能启动该应用程序。重新安装程序可以修复此问题。这是由于一般我们编译的程序都是使用的共享DLL,所以不一定保证其他机器上都有。如果使用静态DLL的话生......
  • 题解 ABC373G【No Cross Matching】/ POJ3565【Ants】
    题目描述年轻的自然主义者比尔在学校里研究蚂蚁。他的蚂蚁以生活在苹果树上的蚜虫为食。每个蚂蚁群需要自己的苹果树来养活自己。比尔有一张地图,上面标有\(n\)个蚂蚁群和\(n\)棵苹果树的坐标。他知道蚂蚁从它们的蚂蚁群到它们的取食地点,然后返回蚂蚁群,都是使用化学标记的路线......