【DG特长生2016 T4】【luogu P1119】灾后重建 / 村庄重建

灾后重建 / 村庄重建

题目链接:luogu P1119

题目大意

有一个无向图,边有权值。
然后对于某个点,它会在某个时刻之后才出现。
然后多个询问,问你在某个时间点中,两个点之间的最短距离。
如果这两个点并没有出现或者中间并没有路就输出 -1。

思路

看到点的个数只有 200 200 200,我们自然会想到用 Floyed。

但是我们可以发现,随着询问,会逐渐的有点由不存在变成存在。
那我们不能重新暴力更新最短路。

我们考虑枚举中转点的时候,因为如果没有某个中转点 x x x,路径就不会经过这个 x x x 点。(除了直接连通)
那我们就可以根据这个性质,把枚举中转点的顺序改成这个点开始存在的时间先后顺序。

那我们就按着时间处理查询(因为题目已经让时间是顺序,所以不需要离线,但是我还是离线了)。
然后按着询问的时间看是否有新的点由不存在变成存在,然后就以它为中转站跑 Floyed。

然后就可以得到那个时刻的距离了。
有一点要注意的是记得判断询问的两个点在哪个时候是否存在,如果不存在,就直接是 − 1 -1 1 了。

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define INF 1e9

using namespace std;

struct quest {
    
    
	int x, y, t, num, ans;
}q[50001];
int n, m, t[201], x, y, w, ckno, nowcan;
int Q, dis[201][201];

int read() {
    
    
	int re = 0, zf = 1;
	char c = getchar();
	while (c < '0' || c > '9') {
    
    
		if (c == '-') zf = -zf;
		c = getchar();
	}
	while (c >= '0' && c <= '9') {
    
    
		re = (re << 3) + (re << 1) + c - '0';
		c = getchar();
	}
	return re * zf;
}

void write(int now) {
    
    
	if (now < 0) {
    
    
		printf("-");
		write(-now);
		return ;
	}
	if (now > 9) write(now / 10);
	putchar(now % 10 + '0');
}

bool cmp1(quest x, quest y) {
    
    
	return x.t < y.t;
}

bool cmp2(quest x, quest y) {
    
    
	return x.num < y.num;
}

void insert(int now) {
    
    //以新加进的点为中转站跑 Floyed
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			dis[i][j] = min(dis[i][j], dis[i][now] + dis[now][j]);
}

void work() {
    
    
	for (int i = 1; i <= Q; i++) {
    
    
		if (q[i].t > q[i - 1].t || i == 1) {
    
    
			while (nowcan < n && t[nowcan + 1] <= q[i].t) {
    
    
				insert(nowcan + 1);//新加进一个点
				dis[nowcan + 1][nowcan + 1] = 0;
				nowcan++;
			}
		}
		
		if (dis[q[i].x][q[i].y] == ckno || t[q[i].x] > q[i].t || t[q[i].y] > q[i].t) q[i].ans = -1;
			else q[i].ans = dis[q[i].x][q[i].y];
	}
}

int main() {
    
    
//	freopen("rebuild.in", "r", stdin);
//	freopen("rebuild.out", "w", stdout);
	
	for (int i = 0; i <= 200; i++)//初始化
		for (int j = 0; j <= 200; j++)
			dis[i][j] = INF;
	ckno = INF;
	
	n = read();
	m = read();
	for (int i = 1; i <= n; i++) t[i] = read();
	
	for (int i = 1; i <= m; i++) {
    
    
		x = read();
		y = read();
		w = read();
		x++;
		y++;
		dis[x][y] = dis[y][x] = w;
	}
	
	Q = read();
	for (int i = 1; i <= Q; i++) {
    
    
		q[i].x = read();
		q[i].y = read();
		q[i].t = read();
		q[i].x++;
		q[i].y++;
		q[i].num = i;
	}
	
	sort(q + 1, q + Q + 1, cmp1);//其实读入已经是排好序了,所以可以不用离线
	
	work();
	
	sort(q + 1, q + Q + 1, cmp2);
	for (int i = 1; i <= Q; i++) {
    
    
		write(q[i].ans);
		putchar('\n');
	}
	
	fclose(stdin);
	fclose(stdout);
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43346722/article/details/115031017