首页 > 其他分享 >P3547 [POI2013] CEN-Price List 题解

P3547 [POI2013] CEN-Price List 题解

时间:2024-08-24 20:05:45浏览次数:6  
标签:emplace int 题解 Price back vis vec POI2013 dis

Description

给定一个 \(n\) 个点 \(m\) 条边的无向图,边权均为 \(a\)。

现在将原来图中满足最短路等于 \(2a\) 所有的点对 \((x,y)\) 之间加一条长度为 \(b\) 的无向边。

给定 \(k\),求点 \(k\) 到所有点的最短路是多少。

\(1\leq n,m\leq 10^5\)。

Solution

首先有个显然的结论是对于所有加边前 \(k\to i\) 的最短路 \(p_1(k)\to p_2\to\dots\to p_{m}(1)\),对于 \(\forall 1\leq i\leq m-2\),一定满足 \(p_i\) 和 \(p_{i+2}\) 没有连边,否则最短路一定会更短。

那么加边之后的最短路就只有三种了:全 \(a\);前面一堆 \(a\) 加 \(0/1\) 个 \(b\);全 \(b\)。

对于前两种情况可以直接在原图上跑 bfs 求出。

考虑怎么做全 \(b\) 的情况。

有一种暴力也是 bfs,每次转移就暴力枚举所有 \(u\to v\to w\),满足 \((u,w)\) 没有边然后让 \(dis_w\leftarrow dis_u+1\)。

但是这样做是 \(O(m^2)\) 的。

注意到对于一个转移 \(u\to v\to w\) 如果 \((u,w)\) 没有边,那么这次转移后 \((v,w)\) 这条边就再也无法作为转移的第二条边进行成功的转移,可以直接删掉。

然后会发现如果 \(u,v,w\) 不构成三元环则每次枚举必然会删掉至少一条边。如果构成三元环,由于三元环个数是 \(O(m\sqrt m)\) 级别的,而每个三元环只会遍历 \(O(1)\) 次,所以复杂度是 \(O(m\sqrt m)\) 的。

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

Code

#include <bits/stdc++.h>

// #define int int64_t

const int kMaxN = 1e5 + 5;

int n, m, s, A, B;
int ans[kMaxN];
std::vector<int> G[kMaxN], _G[kMaxN];

void del(std::vector<int> &vec, int p) {
  std::swap(vec[p], vec[(int)vec.size() - 1]);
  vec.pop_back();
}

void bfs1() {
  static int dis[kMaxN];
  static bool vis[kMaxN];
  std::queue<int> q;
  q.emplace(s), dis[s] = 0, vis[s] = 1;
  for (; !q.empty();) {
    int u = q.front(); q.pop();
    for (auto v : G[u]) {
      if (!vis[v]) {
        dis[v] = dis[u] + 1, vis[v] = 1, q.emplace(v);
      }
    }
  }
  for (int i = 1; i <= n; ++i)
    ans[i] = std::min(dis[i] * A, (dis[i] / 2) * B + (dis[i] % 2) * A);
}

void bfs2() {
  static int dis[kMaxN];
  static bool vis[kMaxN], have[kMaxN];
  std::queue<int> q;
  q.emplace(s), dis[s] = 0, vis[s] = 1;
  for (; !q.empty();) {
    int u = q.front(); q.pop();
    for (auto v : G[u]) have[v] = 1;
    for (auto v : G[u]) {
      std::vector<int> vec;
      for (int i = 0; i < (int)_G[v].size(); ++i) {
        int w = _G[v][i];
        if (w != u && !have[w]) {
          if (!vis[w]) dis[w] = dis[u] + 1, vis[w] = 1, q.emplace(w);
          vec.emplace_back(i);
        }
      }
      for (auto p : vec) {
        del(_G[v], p);
      }
    }
    for (auto v : G[u]) have[v] = 0;
  }
  for (int i = 1; i <= n; ++i)
    if (vis[i])
      ans[i] = std::min(ans[i], dis[i] * B);
}

void dickdreamer() {
  std::cin >> n >> m >> s >> A >> B;
  for (int i = 1; i <= m; ++i) {
    int u, v;
    std::cin >> u >> v;
    G[u].emplace_back(v), G[v].emplace_back(u);
    _G[u].emplace_back(v), _G[v].emplace_back(u);
  }
  memset(ans, 0x3f, sizeof(ans));
  bfs1(), bfs2();
  for (int i = 1; i <= n; ++i) std::cout << ans[i] << '\n';
}

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,题解,Price,back,vis,vec,POI2013,dis
From: https://www.cnblogs.com/Scarab/p/18378175

相关文章

  • 洛谷P2440 木材加工 题解
    这是我找到的一篇很久之前为了让我更好理解二分写的详细题解题目链接code:#include<bits/stdc++.h>#defineintlonglong#defineMAXN0x3f3f3f3f3f3f3f3f#defineMINN-0x3f3f3f3f3f3f3f3f#defineMiraiios::sync_with_stdio(0),cin.tie(0),cout.tie(0);usingnamespa......
  • CF939F Cutlet题解
    前置单调队列(没学过或忘了点这里)简化题意有一块牛排,要求对它烹饪\(2n\)秒,可在给定的\(k\)个时间段中将它翻转任意次,使得牛排两面都受到了\(n\)秒的烹饪。状态设计可以发现当总共煮了\(i\)秒,其中一面如果煮了\(j\)秒,自然可以求出另一面为\(i-j\)秒,所以我们可以......
  • CSP 2023 提高级第一轮 CSP-S 2023初试题 程序阅读第三题解析
    一、程序阅读#include<vector>#include<algorithm>#include<iostream>usingnamespacestd;boolf0(vector<int>&a,intm,intk){ints=0;for(inti=0,j=0;i<a.size();i++){while(a[i]-a[j]>......
  • P10690 Fotile 模拟赛 L 题解
    题目传送门前置知识可持久化字典树|分块思想解法考虑分块预处理整块的答案,散块直接暴力。设\(f_{i,j}\)表示以\(i\)所在的块的左端点为左端点,\(j\)为右端点的最大异或和,可持久化01-Trie维护即可。本题中这种写法比处理整块到整块的答案更容易处理些。整块的答案......
  • 讨论TableLayoutPanel加载缓慢和闪烁问题解决方案
    WinForm加载多个自定义控件时,会出现很严重的闪烁问题,很卡,一块一块的加载(像打开网页时,网络很卡的那种感觉)简直没法忍受。在网上搜索了好久,网上大部分的方法是一下4种,但是都不能有效的解决问题。1、将DoubleBuffered设置true,用双缓存处理Form界面内容加载,可以提高页面显......
  • AtCoder Beginner Contest 367 A ~ F(无D题)题解
    AtCoderBeginnerContest367A~F(̸\notD)几天前就已经vp过了,但是忘写题解了今天才想起来痛,早知道这么简单,我就不在家里摆烂了A.ShoutEveryday罚了好几发,我打比......
  • CF1326F2 Wise Men (Hard Version) 题解
    题目链接点击打开链接题目解法挺难的。可能一步一步推下来也没那么复杂(?基本copytzc_wk的题解/bx肯定不能像\(F1\)用普通的状压求,一个技巧是容斥考虑令\(f_S\)表示\(S\)中为\(1\)的位置\(p_i\)和\(p_{i+1}\)必须认识,为\(0\)的位置随便\(f\)数组相当于答案......
  • P6348 [PA2011] Journeys 题解
    Description一个星球上有\(n\)个国家和许多双向道路,国家用\(1\simn\)编号。但是道路实在太多了,不能用通常的方法表示。于是我们以如下方式表示道路:\((a,b),(c,d)\)表示,对于任意两个国家\(x,y\),如果\(a\lex\leb,c\ley\led\),那么在\(x,y\)之间有一条道路。首都位于......
  • 2018年安徽省赛小学组题解
    T1:移动石子(stone)题目描述期待已久的“清明”假期终于到了。清明节是中华民族几千年来留下的优良传统,它有利于弘扬孝道亲情,唤醒家庭共同记忆,促进家庭成员乃至民族的凝聚力和认同感。小学生卡卡西非常高兴,因为清明前后正是踏青的好时光,他终于可以和小伙伴们一起出去踏青了!然而,天......
  • CF1514D Cut and Stick 题解
    题目传送门前置知识可持久化线段树解法若区间内不存在绝对众数,直接保持这一段即可。若存在绝对众数,贪心地想肯定要尽可能地把其分开还要限制出其他数使其不成为绝对众数。容易发现设绝对众数出现次数为\(cnt\),取\(cnt-1\)个其他数和绝对众数配对最优。但可能其他数不够\(......