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;
}