2021CCPC网络赛I Public Transport System
作者:互联网
2021CCPC网络赛I Public Transport System
题目中每条边边权上存在两个值,考虑将其变成一个值后进行单源最短路算法。
不难看出,一条边的边权有取决于上条边的边权,可以想到将所有可能出现的边权与上条边权情况全部表达出来。那么对于一个入度为\(u\),出度为\(v\)的点,此点将会被拆为\(u\)个不同节点,每个节点上将有\(v\)个出度。出现了\(u\times v\)条边,最终复杂度将达到\(O(m^2logm)\)无法接受。
考虑优化此过程,朴素的想法为通过添加若干个点,使得优惠与不优惠情况完全分隔开,但显然是无法直接添加的——由于前一个边权大小不同,所以优惠的分界线也是不同的。
但优惠具有单调性——若有\(a_i<a_j<a_k\)且\(a_i>a_{now}\),那么\(a_i,a_j,a_k\)均能享受到优惠。添边时也只需要添加出\(a_{now}->a_i\)的优惠边即可。大于\(a_i\)的所达位置可以添加边权为\(0\)的边。
所以在读入所有边后,按边权对其\(a\)排序,考虑\(u->v\)的一条边边权为\(a_i\),那么遍历所有\(v\)的出边,找到第一个边\(pos\)使得\(a_{pos}>a_i\),同时连接\(u\)和新节点。具体可以通过代码细化:
#include <iostream>
#include <string.h>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <set>
#include <vector>
#include <queue>
#include <map>
#include <unordered_map>
#define Lint long long
#define pi acos(-1.0)
using namespace std;
const int N = 2e5 + 10;
int T, n, m, tot;
struct node
{
Lint a, b;
int y;
};
vector<node> edge[N];
bool cmp(node x, node y)
{
return x.a < y.a;
}
struct addnode
{
Lint a, b;
int y, id;
};
vector<addnode> sort_edge[N];
struct work
{
struct Node
{
int x;
Lint z;
bool operator<(const Node &a) const
{
return z > a.z;
}
};
priority_queue<Node> q;
vector<Node> v[N * 2 + 10];
Lint dis[N * 2 + 10];
int vis[N * 2 + 10];
void init(int x)
{
for (int i = 1; i <= x; ++i)
{
v[i].clear();
dis[i] = 1e15;
vis[i] = 0;
}
}
void add(int x, int y, Lint z)
{
v[x].push_back({y, z});
}
void debug(int x){
for(int i=1;i<=x;++i){
for(auto j:v[i]){
cout<<i<<" "<<j.x<<" "<<j.z<<"\n";
}
puts("*******************");
}
}
void Dijkstra()
{
dis[1] = 0;
q.push({1, dis[1]});
while (q.size())
{
auto u = q.top();
q.pop();
if (vis[u.x])
{
continue;
}
vis[u.x] = 1;
for (auto i : v[u.x])
{
if (dis[i.x] > dis[u.x] + i.z)
{
dis[i.x] = dis[u.x] + i.z;
q.push({i.x, dis[i.x]});
}
}
}
}
void print()
{
for (int i = 1; i <= n; ++i)
{
if (dis[i] > 1e14)
{
cout << "-1 ";
}
else
cout << dis[i] << " ";
}
cout << "\n";
}
} work;
void build(int u, int v, Lint w, Lint a)
{
int l = 0, r = sort_edge[v].size() - 1, pos = -1;
while (l <= r)
{
int mid = (l + r) >> 1;
if (sort_edge[v][mid].a > a)
{
pos = mid;
r = mid - 1;
}
else
l = mid + 1;
}
if (pos == -1)
{
work.add(u, v, w);
}
else
work.add(u, sort_edge[v][pos].id, w);
}
void solve()
{
int x, y;
Lint a, b;
cin >> n >> m;
for (int i = 1; i <= n; ++i)
{
edge[i].clear();
sort_edge[i].clear();
}
for (int i = 1; i <= m; ++i)
{
cin >> x >> y >> a >> b;
edge[x].push_back({a, b, y});
}
for (int i = 1; i <= n; ++i)
sort(edge[i].begin(), edge[i].end(), cmp);
tot = n;
for (int i = 1; i <= n; ++i)
{
for (int j = 0; j < edge[i].size(); ++j)
{
sort_edge[i].push_back({edge[i][j].a, edge[i][j].b, edge[i][j].y, ++tot});
}
}
work.init(tot);
for (int i = 1; i <= n; ++i)
{
int Len = sort_edge[i].size();
if (Len)
{
work.add(sort_edge[i][Len - 1].id, i, 0);
}
for (int j = 0; j < Len - 1; ++j)
{
work.add(sort_edge[i][j].id, sort_edge[i][j + 1].id, 0);
}
for (int j = 0; j < Len; ++j)
{
build(i, edge[i][j].y, edge[i][j].a, edge[i][j].a);
}
for (int j = 0; j < Len; ++j)
{
build(sort_edge[i][j].id, sort_edge[i][j].y, sort_edge[i][j].a - sort_edge[i][j].b, sort_edge[i][j].a);
}
}
// work.debug(tot+2);
work.Dijkstra();
work.print();
}
int main()
{
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(0);
cin >> T;
while (T--)
solve();
return 0;
}
sort_edge[i].push_back({edge[i][j].a, edge[i][j].b, edge[i][j].y, ++tot});
该语句中,tot为新加入的点的编号,访问此点实际为通过打折方式访问对应目标点。
int Len = sort_edge[i].size();
if (Len)
{
work.add(sort_edge[i][Len - 1].id, i, 0);
}
for (int j = 0; j < Len - 1; ++j)
{
work.add(sort_edge[i][j].id, sort_edge[i][j + 1].id, 0);
}
若此点存在能导出的端点,那么导出端点间将连出一条边,对应了上述的贪心过程,给予了较大边权也可享受全部优惠的效果。
for (int j = 0; j < Len; ++j)
{
build(i, edge[i][j].y, edge[i][j].a, edge[i][j].a);
}
for (int j = 0; j < Len; ++j)
{
build(sort_edge[i][j].id, sort_edge[i][j].y, sort_edge[i][j].a - sort_edge[i][j].b, sort_edge[i][j].a);
}
上述二分过程,即便是可以打折,依然可以选择原价通过,只需添加一次即可,因为后续点可以通过边权为0边到达。
这道题编码困难在分清楚新加入的点的含义——通过新加入点实际上是进行了打折这一操作,而新加入点之间的连边则是为了能够传达打折这一效果。
标签:sort,int,边权,System,Len,2021CCPC,edge,include,Transport 来源: https://www.cnblogs.com/nuist-wzy/p/16478745.html