JZOJ 6897. 【2020.11.27提高组模拟】第一题(最短路)

JZOJ 6897. 【2020.11.27提高组模拟】第一题

题解

  • 这是一个并不确定复杂度是否正确的解法。
  • 看到从若干点出发然后询问多次是否感染,让我想到了从所有初始被感染的点一起跑最短路,最后再处理询问,若询问的时间大于等于被感染的时间则为YES,否则为NO。每一次 4 4 4操作则对应时间 + 1 +1 +1
  • 但是要考虑封城的问题,把每个点封城的若干段时间区间存下来依次按编号、时间排序,注意最后可能有城市直到操作结束都没解封也要算上。在最短路中转移的时候,设当前从 x x x转移到 y y y,则通过二分找到在 d i s x dis_x disx后面最近的且 x x x y y y都没被封城的时间 t t t,用 t t t更新 d i s y dis_y disy
  • 具体做法的话,先一次二分找到只满足 x x x没被封的时间,再找该时间后 y y y没被封的时间,若相同则退出,否则 x x x y y y交替找下去。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define N 500010
int last[N], nxt[N * 2], to[N * 2], len = 0;
int a[N], p[N], s = 0, tot = 0;
int dis[N], vi[N];
struct ci {
	int x, l, r;
}lo[N];
struct {
	int x, t; 
}qu[N];
queue<int> q;
int cmp(ci x, ci y) {
	if(x.x == y.x) return x.l < y.l;
	return x.x < y.x;
}
void add(int x, int y) {
	to[++len] = y;
	nxt[len] = last[x];
	last[x] = len;
}
int read() {
	char x = getchar();
	int s = 0;
	while(x < '0' || x > '9') x = getchar();
	while(x >= '0' && x <= '9') s = s * 10 + x - 48, x = getchar();
	return s;
}
int find(int x, int t) {
	int l = 1, r = s, R = 0;
	while(l <= r) {
		int mid = (l + r) / 2;
		if(lo[mid].x > x) r = mid - 1;
		else if(lo[mid].x < x) l = mid + 1;
		else {
			if(lo[mid].l <= t) R = lo[mid].r, l = mid + 1; else r = mid - 1;
		}
	}
	R = max(t, R);
	return R;
}
int main() {
	int i, n = read(), m = read(), Q = read(), x, y;
	for(i = 1; i < n; i++) {
		x = read(), y = read();
		add(x, y), add(y, x);
	}
	for(i = 1; i <= m; i++) a[i] = read();
	int t = 0;
	memset(p, 255, sizeof(p));
	for(i = 1; i <= Q; i++) {
		int op = read();
		if(op == 1) {
			p[read()] = t;
		}
		else if(op == 2) {
			x = read();
			if(p[x] != t) lo[++s].x = x, lo[s].l = p[x], lo[s].r = t;
			p[x] = -1;
		}
		else if(op == 3) {
			qu[++tot].x = read(), qu[tot].t = t;
		}
		else if(op == 4) {
			t++;
		}
	}
	for(i = 1; i <= n; i++) if(p[i] != -1) {
		lo[++s].x = i, lo[s].l = p[i], lo[s].r = t;
	}
	sort(lo + 1, lo + s + 1, cmp);
	for(i = s - 1; i > 0; i--) {
		if(lo[i + 1].x == lo[i].x && lo[i].r >= lo[i + 1].l) lo[i].r = lo[i + 1].r;
	}
	memset(dis, 127, sizeof(dis));
	for(i = 1; i <= m; i++) {
		vi[a[i]] = 1, dis[a[i]] = 0;
		q.push(a[i]);
	}
	while(!q.empty()) {
		x = q.front();
		q.pop();
		int out = find(x, dis[x]);
		for(i = last[x]; i; i = nxt[i]) {
			y = to[i];
			int ti = out, in;
			while(ti + 1 < dis[y]) {
				in = find(y, ti);
				ti = find(x, in);
				if(ti == in) break;
			}
			if(ti + 1 < dis[y]) {
				dis[y] = ti + 1;
				if(!vi[y]) {
					vi[y] = 1;
					q.push(y);
				}
			}
		}
		vi[x] = 0;
	}
	for(i = 1; i <= tot; i++) {
		if(dis[qu[i].x] <= qu[i].t) puts("Y"); else puts("N");
	}
	return 0;
}
原文地址:https://www.cnblogs.com/LZA119/p/14279486.html