P4814 题解

解题思路

对于每条边 \((u,v)\),权值为 \(w\),假设存在一条经过这一条边的路径,其最短距离为 \(a\)\(u\) 的最短路加上 \(v\)\(b\) 的最短距离加上 \(w\),若这个值都大于 \(d\),则不可能关闭这条边。

由于边权非负,所以可采用 dijkstra 来处理最短路。因为为有向边,所以可以再建反图处理 \(v\)\(b\) 的最短路。

然而如果每次询问都暴力查找有多少条要关闭的边,时间复杂度为 \(\mathcal{O}(q\times m)\),预计得分 \(80\text{pts}\)

从而就衍生出了离线处理,因为 \(d\) 从小到大排序后对于上一个 \(d\) 要关闭的这一次一定要关,从而离线时间复杂度为 \(\mathcal{O}(n)\),所以总时间复杂度 \(\mathcal{O}(m\times\log_2m+q\times\log_2q+n)\)

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 5;
struct edge {
  int v, w;
};
struct node {
  int x, d;
  bool operator < (const node &x) const {
    return d > x.d;
  }
};
int n, m, a, b, dis[N][2];
struct query {
  int d, id, ans;
} q[N];
bool vis[N];
vector<edge> e1[N], e2[N];
struct edg {
  int x, y, l, c;
  bool operator < (const edg &p) const {
    return dis[x][0] + l + dis[y][1] < dis[p.x][0] + p.l + dis[p.y][1];
  }
} ed[N];
inline void dij(vector<edge> e[], int s, int f) {
  memset(vis, 0, sizeof(vis));
  priority_queue<node> pq;
  pq.push({s, 0});
  for(int i = 1; i <= n; i++) {
    dis[i][f] = 1e9;
  }
  dis[s][f] = 0;
  while(!pq.empty()) {
    node tmp = pq.top();
    pq.pop();
    vis[tmp.x] = 0;
    for(edge i : e[tmp.x]) {
      if(dis[i.v][f] > dis[tmp.x][f] + i.w) {
        dis[i.v][f] = dis[tmp.x][f] + i.w;
        if(!vis[i.v]) {
          vis[i.v] = 1;
          pq.push({i.v, dis[i.v][f]});
        }
      }
    }
  }
  return ;
}
inline bool cmp1(query x, query y) {
  return x.d < y.d;
}
inline bool cmp2(query x, query y) {
  return x.id < y.id;
}
signed main() {
  ios::sync_with_stdio(0);
  cin.tie(0), cout.tie(0);
  cin >> n >> m >> a >> b;
  for(int i = 1; i <= m; i++) {
    int x, y, l, c;
    cin >> x >> y >> l >> c;
    ed[i] = {x, y, l, c};
    e1[x].push_back({y, l});
    e2[y].push_back({x, l});
  }
  dij(e1, a, 0);
  dij(e2, b, 1);
  sort(ed + 1, ed + m + 1);
  int Q;
  cin >> Q;
  for(int i = 1; i <= Q; i++) {
    cin >> q[i].d;
    q[i].id = i;
  }
  sort(q + 1, q + Q + 1, cmp1);
  int ans = 0, t = 1;
  for(int i = 1; i <= Q; i++) {
    while(t <= m && dis[ed[t].x][0] + ed[t].l + dis[ed[t].y][1] <= q[i].d) {
      ans += ed[t].c;
      ++t;
    }
    q[i].ans = ans;
  }
  sort(q + 1, q + Q + 1, cmp2);
  for(int i = 1; i <= Q; i++) {
    cout << q[i].ans << '\n';
  }
  return 0;
}
posted @ 2023-10-18 22:25  cyf1208  阅读(6)  评论(0编辑  收藏  举报