首页 > 其他分享 >P6348 [PA2011] Journeys 题解

P6348 [PA2011] Journeys 题解

时间:2024-08-23 22:50:43浏览次数:6  
标签:le Journeys int 题解 kMaxN vec P6348 id dis

Description

一个星球上有 \(n\) 个国家和许多双向道路,国家用 \(1\sim n\) 编号。

但是道路实在太多了,不能用通常的方法表示。于是我们以如下方式表示道路:\((a,b),(c,d)\) 表示,对于任意两个国家 \(x,y\),如果 \(a\le x\le b,c\le y\le d\),那么在 \(x,y\) 之间有一条道路。

首都位于 \(P\) 号国家。你想知道 \(P\) 号国家到任意一个国家最少需要经过几条道路。保证 \(P\) 号国家能到任意一个国家。

\(1\le n\le 5\times 10^5\),\(1\le m\le 10^5\),\(1\le a\le b\le n\),\(1\le c\le d\le n\)。

Solution

这里给出一个比较新颖的做法。

首先如果暴力建图显然会超时,而超时的原因是对于每个道路都两两建边过于浪费,因为对于一个 \([a,b]\to[c,d]\) 的道路,只需要让 \([a,b]\) 中 \(dis\) 最小的那个位置去更新 \([c,d]\)。

考虑类似 dijkstra 的过程,按 \(dis\) 从小到大确定每个 \(dis_x\),同时维护一个关于转移边的优先队列。假如当前确定了 \(dis_x\),就暴力枚举所有还没有更新过的道路 \([a,b]\to[c,d]\),将 \([c,d,dis_x+1]\) 加入优先队列,表示可以让 \([c,d]\) 这个区间里的 \(dis\) 更新为 \(dis_x+1\)。

由于这里是从小到大确定 \(dis\) 的,所以每次取出队头的转移 \([l,r,v]\) 只需要暴力找到 \([l,r]\) 中还没有确定 \(dis\) 的位置更新为 \(v\),同时维护优先队列即可。

时间复杂度:\(O\left(\left(n+m\right)\log^2n\right)\)。

Code

#include <bits/stdc++.h>

#define int int64_t

const int kMaxN = 5e5 + 5;

int n, m, s;
int l1[kMaxN], r1[kMaxN], l2[kMaxN], r2[kMaxN], dis[kMaxN];
std::set<int> st, t[kMaxN * 4];
std::queue<std::tuple<int, int, int>> q;

void update(int x, int l, int r, int id, int op) {
  int ql = l1[id], qr = r1[id];
  if (l > qr || r < ql) {
    return;
  } else if (l >= ql && r <= qr) {
    if (op == 1) t[x].emplace(id);
    else t[x].erase(id);
    return;
  }
  int mid = (l + r) >> 1;
  update(x << 1, l, mid, id, op), update(x << 1 | 1, mid + 1, r, id, op);
}

void getvec(int x, int l, int r, int ql, std::vector<int> &vec) {
  for (auto id : t[x]) vec.emplace_back(id);
  if (l == r) return;
  int mid = (l + r) >> 1;
  if (ql <= mid) getvec(x << 1, l, mid, ql, vec);
  else getvec(x << 1 | 1, mid + 1, r, ql, vec);
}

void upd(int x) {
  std::vector<int> vec;
  st.erase(x), getvec(1, 1, n, x, vec);
  for (auto id : vec) {
    update(1, 1, n, id, -1);
    q.emplace(l2[id], r2[id], dis[x] + 1);
  }
}

void dijkstra() {
  for (int i = 1; i <= n; ++i) st.emplace(i);
  for (int i = 1; i <= m; ++i) update(1, 1, n, i, 1);
  memset(dis, 0x3f, sizeof(dis));
  dis[s] = 0, upd(s);
  for (; !q.empty();) {
    auto [l, r, val] = q.front(); q.pop();
    for (auto it = st.lower_bound(l); it != st.end() && *it <= r; it = st.lower_bound(l)) {
      int u = *it;
      dis[u] = val, upd(u);
    }
  }
}

void dickdreamer() {
  std::cin >> n >> m >> s;
  for (int i = 1; i <= m; ++i) {
    std::cin >> l1[i] >> r1[i] >> l2[i] >> r2[i];
    l1[i + m] = l2[i], r1[i + m] = r2[i], l2[i + m] = l1[i], r2[i + m] = r1[i];
  }
  m *= 2;
  dijkstra();
  for (int i = 1; i <= n; ++i) std::cout << dis[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;
}

标签:le,Journeys,int,题解,kMaxN,vec,P6348,id,dis
From: https://www.cnblogs.com/Scarab/p/18377205

相关文章

  • 2018年安徽省赛小学组题解
    T1:移动石子(stone)题目描述期待已久的“清明”假期终于到了。清明节是中华民族几千年来留下的优良传统,它有利于弘扬孝道亲情,唤醒家庭共同记忆,促进家庭成员乃至民族的凝聚力和认同感。小学生卡卡西非常高兴,因为清明前后正是踏青的好时光,他终于可以和小伙伴们一起出去踏青了!然而,天......
  • CF1514D Cut and Stick 题解
    题目传送门前置知识可持久化线段树解法若区间内不存在绝对众数,直接保持这一段即可。若存在绝对众数,贪心地想肯定要尽可能地把其分开还要限制出其他数使其不成为绝对众数。容易发现设绝对众数出现次数为\(cnt\),取\(cnt-1\)个其他数和绝对众数配对最优。但可能其他数不够\(......
  • 题解:P10906 [蓝桥杯 2024 国 B] 合法密码
    本来以为字符串多大,结果就这点,直接暴力。枚举起始点,对于每个起始点枚举后面\(8\sim16\)位有没有能用的即可。最后答案为\(400\)。附:计算代码枚举代码如下:for(inti=0;i<n;++i){for(intlength=8;length<=16;++length){if(i......
  • 题解:P10903 [蓝桥杯 2024 省 C] 商品库存管理
    题目大意有一个初始化为\(0\)的长度为\(n\)的序列,现有\(m\)个操作,每次将区间\([L,R]\)中的数量加\(1\),求如果不做某个操作将会有多少个数量为\(0\)的量。解题思路当看见这句话时就想到了差分,这题我们可以使用差分先处理将所有的操作执行后的数组,然后在算出如果减......
  • P10404 「XSOI-R1」原神数 题解
    一篇题解需要一张头图。容易发现超过十位的数都不是原神数,因为只有十个数字,不可能保证十一个位置互不相同。同时恰好十位的数也不可能是原神数,因为数位互不相同的十位数的数位和为\(45\),被\(3\)整除,一定是\(3\)的倍数。于是把原神数的范围缩小到\([1,10^9)\)。显然不......
  • P10528 [XJTUPC2024] 崩坏:星穹铁道 题解
    求方案数,分多种情况,不难想到DP。设\(dp_{i,j}\)表示已经行动\(i\)次,剩余战技点个数为\(j\)的方案数,容易得到以下转移方程。\(a_i=1\)时,有\[dp_{i,j}=\begin{cases}0,&j=0,\\dp_{i-1,j-1},&1\leqslantj\leqslant4,\\dp_{i-1,j-1}+dp_{i......
  • LGP10702 [SNCPC2024] 下棋题解
    P10702[SNCPC2024]下棋本蒟蒻的第一篇题解定位博弈论(nim)+进制转换相关知识OIWIKI博弈论NIM进制转换正题读题所有k进制下所有数位的乘积为自身因子的数。他称之为LNC数。给出x枚棋子,然后LNC选定一个整数k(k≥2)。随后他们交替取走若干枚棋子,要求取走的棋......
  • 【题解】Solution Set - NOIP2024集训Day14 CDQ分治
    【题解】SolutionSet-NOIP2024集训Day14CDQ分治https://www.becoder.com.cn/contest/5482「CF364E」EmptyRectangles*3000摆烂了。「SDOI2011」拦截导弹CDQ的例题,之前做过(现在试图自己再做出来。第二问只用在第一问里面记录每一次是从哪个\(j\)​转移过来的,以及......
  • P10559 [ICPC2024 Xi'an I] The Last Cumulonimbus Cloud 题解
    这种题有一个常见的根号分治做法:设\(d\)为度数,显然有\(O(1)\)修改单点,\(O(d)\)查询邻域和\(O(d)\)修改邻域,\(O(1)\)查询单点两种暴力。对度数大于\(\sqrtn\)的点使用前者,度数小于等于\(\sqrtn\)的点使用后者,可以做到\(O(m\sqrtn)\)的时间复杂度。这种做法的本......
  • CF1575G GCD Festival 题解
    考虑欧拉反演\[\sum\limits_{d\midn}\varphi(d)=n\]则原式可以化为\[\begin{align*}&\sum\limits_{i=1}^n\sum\limits_{j=1}^n\gcd(a_i,a_j)\cdot\gcd(i,j)\\=&\sum\limits_{i=1}^n\sum\limits_{j=1}^n\gcd(a_i,a_j)\sum\li......