【BZOJ5415】【UOJ393】【NOI2018】归程

本文介绍了一种基于Kruskal算法的重构树方法,并结合倍增技巧优化查询过程。适用于解决带有路径查询的问题,通过预处理实现了高效的路径查询。算法时间复杂度为O(NLogN+QLogN),适合解决大规模数据集问题。

【题目链接】

【思路要点】

  • Kruskal K r u s k a l 重构树上倍增。
  • 时间复杂度 O(NLogN+QLogN) O ( N L o g N + Q L o g N )

【代码】


#include<bits/stdc++.h>

using namespace std;
const int MAXN = 4e5 + 5;
const int MAXLOG = 20;
const int INF = 2e9;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {
  int f = 1; x = 0;
  char ch = getchar();
  for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -f;
  for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
  x *= f;
}
struct edge {int dest, len; };
struct info {int x, y, l, h; };
struct temp {int pos, dist; };
bool operator < (temp a, temp b) {return a.dist > b.dist; }
int n, m, newn, dist[MAXN], height[MAXN];
int father[MAXN][MAXLOG], f[MAXN];
int q, type, s;
info b[MAXN];
vector <edge> a[MAXN];
void ShortestPath() {
  static bool finished[MAXN];
  for (int i = 1; i <= n; i++)
      dist[i] = INF, finished[i] = false;
  static priority_queue <temp> Heap;
  while (!Heap.empty()) Heap.pop();
  dist[1] = 0; Heap.push((temp) {1, 0});
  while (!Heap.empty()) {
      while (!Heap.empty() && finished[Heap.top().pos]) Heap.pop();
      if (Heap.empty()) return;
      temp tmp = Heap.top(); Heap.pop();
      finished[tmp.pos] = true;
      for (unsigned i = 0; i < a[tmp.pos].size(); i++)
          if (tmp.dist + a[tmp.pos][i].len < dist[a[tmp.pos][i].dest]) {
              dist[a[tmp.pos][i].dest] = tmp.dist + a[tmp.pos][i].len;
              Heap.push((temp) {a[tmp.pos][i].dest, dist[a[tmp.pos][i].dest]});
          }
  }
}
int F(int x) {
  if (f[x] == x) return x;
  else return f[x] = F(f[x]);
}
bool cmp(info a, info b) {
  return a.h > b.h;
}
int query(int pos, int h) {
  for (int i = MAXLOG - 1; i >= 0; i--)
      if (h < height[father[pos][i]]) pos = father[pos][i];
  return dist[pos];
}
int main() {
  int T; read(T);
  while (T--) {
      read(n), read(m);
      for (int i = 1; i <= n; i++)
          a[i].clear();
      for (int i = 1; i <= m; i++) {
          int x, y, l, h;
          read(x), read(y), read(l), read(h);
          a[x].push_back((edge) {y, l});
          a[y].push_back((edge) {x, l});
          b[i] = (info) {x, y, l, h};
      }
      sort(b + 1, b + m + 1, cmp);
      ShortestPath();
      newn = n;
      for (int i = 1; i <= n; i++) {
          f[i] = i;
          height[i] = INF;
      }
      memset(father, 0, sizeof(father));
      for (int i = 1; i <= m; i++) {
          int tx = F(b[i].x);
          int ty = F(b[i].y);
          if (tx != ty) {
              newn++;
              f[newn] = newn;
              dist[newn] = min(dist[tx], dist[ty]);
              height[newn] = b[i].h;
              f[tx] = f[ty] = newn;
              father[tx][0] = father[ty][0] = newn;
          }
      }
      for (int i = newn; i >= 1; i--)
      for (int j = 1; j < MAXLOG; j++)
          father[i][j] = father[father[i][j - 1]][j - 1];
      int lastans = 0;
      read(q), read(type), read(s);
      while (q--) {
          long long v, p;
          read(v), read(p);
          v = (v + type * lastans - 1) % n + 1;
          p = (p + type * lastans) % (s + 1);
          printf("%d\n", lastans = query(v, p));
      }
  }
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值