Luogu P1119 灾后重建
在洛谷中查看
解法1(我想的解法,不完全正确):
很常见的套路:将询问按时间排序。时间复杂度:\(O(q\;m\;logn)\),即 \(8 \times 10^9\),有一些特殊情况特判了,并且开了 \(O2\) 才能过。
非常麻烦有没有,但我对拍的时候发现了一组数据很奇怪,待会给你们看看,我看看能不能 hack
哦,我那个 hack \(t\) 是会下降的,题读错了(捂脸)
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
#define fi first
#define se second
const int N = 205, M = 2e4 + 5, Q = 5e4 + 5, element = 1e5 + 5;//注意数组大小,有点乱
int n, m, query_num, t[N], timeline[N], nxtdate[element], ans[Q];
struct edge {
int u, v, w;
};
vector<edge> g[element]; //每个时间都存一下
struct Query {
int u, v, t, id;
}q[Q];
inline int read() {
int s = 0, f = 1; char c = getchar();
while (c < '0' || c>'9') { if (c == '-')f = -1; c = getchar(); }
while (c >= '0' && c <= '9') { s = (s << 1) + (s << 3) + (c ^ 48); c = getchar(); }
return s * f;
}
bool cmp(Query a, Query b) {
return a.t < b.t;
}
int road[N][N], dis[N];
priority_queue<P, vector<P>, greater<P> > Queue;
void dijkstra(int st) {
memset(dis, 0x3f3f3f3f, sizeof(dis));
dis[st] = 0; Queue.push(P(0, st));
while (!Queue.empty()) {
P h = Queue.top();
Queue.pop();
int u = h.se;
if (dis[u] < h.fi)continue;
for (int i = 1; i <= n; i++) {
if (dis[i] > dis[u] + road[u][i]) {
dis[i] = dis[u] + road[u][i];
Queue.push(P(dis[i], i));
}
}
}
}
int main() {
n = read(), m = read();
for (int i = 1; i <= n; i++)t[i] = timeline[i] = read();
for (int i = 1; i <= m; i++) {
int u = read(), v = read(), w = read();
u++, v++;
g[max(t[u], t[v])].push_back(edge{ u,v,w });
}
sort(timeline + 1, timeline + n + 1);//将时间线从小到大排序
timeline[0] = -1; timeline[n + 1] = element - 1;//将timeline[0]的值设为 -1,并将timeline[n+1]的值设得比所有时间大,但也不能越界。让它有起点,有终点
for (int i = 1; i <= n + 1; i++)nxtdate[timeline[i - 1]] = timeline[i];//像链表一样串起来
query_num = read();//变量名重了就很难受
for (int i = 1; i <= query_num; i++)q[i] = Query{ read() + 1,read() + 1,read(),i };
sort(q + 1, q + query_num, cmp);
memset(road, 0x3f, sizeof(road));//初始化
/*----------------------*/
//下面时间复杂度是 O( q m logn ) 的,即最多 8e9 很悬
int now_time = -1;
for (int i = 1; i <= query_num; i++) {
if (q[i].u == q[i].v) { ans[q[i].id] = 0; continue; }//在同一个点时,不管建没建好,直接输出0
if (t[q[i].u] > q[i].t || t[q[i].v] > q[i].t) { ans[q[i].id] = -1; continue; }
while (nxtdate[now_time] <= q[i].t) {//总共只会有n次
now_time = nxtdate[now_time];
for (int build = 0; build < g[now_time].size(); build++) {
int u = g[now_time][build].u, v = g[now_time][build].v, w = g[now_time][build].w;
road[u][v] = road[v][u] = min(road[u][v], w);
}
}
dijkstra(q[i].u);
ans[q[i].id] = (dis[q[i].v] == 0x3f3f3f3f) ? -1 : dis[q[i].v];
}
for (int i = 1; i <= query_num; i++)cout << ans[i] << endl;
return 0;
}
等一下,发现一个问题:数据保证了 t 是不下降的。啊这,第二次做时才发现,以后一定要好好看题啊。
解法2(正解):
正解很简单,我就说一下为什么 当修建好一个村庄时,再将与之相连的道路开通 的解法是错误的,其实这个事我在浙江集训营时也想过想出来了,这里再说一遍。
$\ $
为什么必须在一开始就把所有道路开通呢?因为如果现在不开通,而是以后开通,那么某些点就不能通过当前这个中转点中转了。
更清楚的说。如果当前这个中转点是 \(k\),某两个点 \(x\) 和 \(y\) 是在以后才开通的,那么 \(x\) 和 \(y\) 就不会再通过 \(k\) 中转了,但某些时候通过 \(k\) 中转才是最优的。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define debug(x) cout<<#x<<' '<<x<<endl;
const int N = 205;
int n, m, q, t[N];
int road[N][N];
struct edge {
int to, w;
};
vector<edge> Graph[N];
inline int read() {
int s = 0, f = 1; char c = getchar();
while (c < '0' || c>'9') { if (c == '-')f = -1; c = getchar(); }
while (c >= '0' && c <= '9') { s = (s << 3) + (s << 1) + (c ^ 48); c = getchar(); }
return s * f;
}
int main() {
n = read(), m = read();
for (int i = 1; i <= n; i++)t[i] = read();
memset(road, 0x3f, sizeof(road));//设为无穷大
for (int i = 1; i <= m; i++) {
int u = read(), v = read(), w = read();
u++, v++;
road[u][v] = road[v][u] = w;
}
int nowtime = 0; t[0] = -1; t[n + 1] = 1e5 + 1;//让它有起点,有终点
q = read();
for (int i = 1; i <= n; i++)road[i][i] = 0;//自己到自己始终是0,不管修没修好
while (q--) {
int u = read(), v = read(), Time = read();
u++, v++;
while (t[nowtime + 1] <= Time) {
nowtime++; //注意一下判断条件
for (int i = 1; i <= n; i++)for (int j = i + 1; j <= n; j++)road[i][j] = road[j][i] = min(road[i][j], road[i][nowtime] + road[nowtime][j]);
}
if (t[u] > t[nowtime] || t[v] > t[nowtime] || road[u][v] == 0x3f3f3f3f)cout << -1 << endl;
else cout << road[u][v] << endl;
}
return 0;
}

浙公网安备 33010602011771号