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