• 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;
    }
    
  • 相关阅读:
    JavaScript遍历表单元素
    JavaScript实现按钮改变网页背景色
    JavaScript实现指定格式字符串表单校验
    jQuery实现数字时钟
    Python使用递归绘制谢尔宾斯基三角形
    Python使用函数模拟“汉诺塔”过程
    Python使用函数实现杨辉三角
    CSS简单样式练习(七)
    CSS简单样式练习(六)
    cstring to char *例子
  • 原文地址:https://www.cnblogs.com/LZA119/p/14279486.html
Copyright © 2020-2023  润新知