• [HNOI2018]游戏[拓扑排序]


    题意

    题目链接

    分析

    • 先将没有锁的房间缩点,首先有一个 (O(n^2)) 的想法:从每个点出发,每次检查能否向两边扩张。
    • 容易发现门和门之间如果有锁,必然只有一方能够开锁(只有一把钥匙),并且能够开一扇门的位置一定是一个区间 ([l,r])。假设门 (p<l) ,则区间内的所有门都为 (leftarrow) 。如果扩展顺序为 (l)(r) 就可以保证对于开 (p​) 门这个操作只被进行一次,而后面的位置可以继承这个可行区间。
    • 所以如果对于门 (a),如果钥匙在 (a) 左边,就连边 (a+1 ightarrow a) ,反之同理。按照拓扑序扩展就可以保证扩展次数至多为 (m) 次。
    • 时间复杂度 (O(n+m))

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    #define go(u) for(int i = head[u], v = e[i].to; i; i=e[i].lst, v=e[i].to)
    #define rep(i, a, b) for(int i = a; i <= b; ++i)
    #define pb push_back
    #define re(x) memset(x, 0, sizeof x)
    inline int gi() {
        int x = 0,f = 1;
        char ch = getchar();
        while(!isdigit(ch)) { if(ch == '-') f = -1; ch = getchar();}
        while(isdigit(ch)) { x = (x << 3) + (x << 1) + ch - 48; ch = getchar();}
        return x * f;
    }
    template <typename T> inline bool Max(T &a, T b){return a < b ? a = b, 1 : 0;}
    template <typename T> inline bool Min(T &a, T b){return a > b ? a = b, 1 : 0;}
    const int N = 1e6 + 7;
    int n, m, p, ndc;
    int x[N], y[N], pos[N], du[N], id[N], L[N], R[N];
    bool lck[N];
    vector<int>G[N];
    queue<int>Q;
    void solve() {
    	rep(i, 1, ndc) L[i] = R[i] = i;
    	rep(i, 1, ndc) if(!du[i]) Q.push(i);
    	while(!Q.empty()) {
    		int u = Q.front();Q.pop();
    		while(1) {
    			bool fg = 0;
    			if(u > 1 && L[u] <= pos[L[u] - 1] && pos[L[u] - 1] <= R[u]) fg = 1, L[u] = L[L[u] - 1];
    			if(u < ndc && L[u] <= pos[R[u]] && pos[R[u]] <= R[u]) fg = 1, R[u] = R[R[u] + 1];
    			if(!fg) break;
    		}
    		for(auto v:G[u]) {
    			if(--du[v] == 0) Q.push(v);
    		}
    	}
    }
    int main() {
    	n = gi(), m = gi(), p = gi();
    	rep(i, 1, m) {
    		x[i] = gi(), y[i] = gi();
    		lck[x[i]] = 1;
    	}
    	id[1] = ++ndc;
    	rep(i, 2, n) {
    		if(lck[i - 1]) id[i] = ++ndc;
    		else id[i] = id[i - 1];
    	}
    	rep(i, 1, m) pos[id[x[i]]] = id[y[i]];
    	
    	rep(i, 1, m) {
    		x[i] = id[x[i]], y[i] = id[y[i]];
    		if(y[i] <= x[i]) G[x[i] + 1].pb(x[i]), ++du[x[i]];
    		if(y[i] > x[i]) G[x[i]].pb(x[i] + 1), ++du[x[i] + 1];
    	}
    	solve();
    	while(p--) {
    		int s = id[gi()], t = id[gi()];
    		if(L[s] <= t && t <= R[s]) puts("YES");
    		else puts("NO");
    	}
    	return 0;
    }
    
  • 相关阅读:
    vue vxetable表格
    Microsoft Visual Studio 配置汇编语言开发环境
    前端代码工程学
    面向未来的100项颠覆性技术创新
    打印程序
    A Sketch of the Biggest Idea in Software Architecture
    2021 年年度最佳开源软件
    如何让一个层垂直居中
    最佳Icon图标库推荐,收藏等于学会
    asp.net mvc框架之Filter的使用
  • 原文地址:https://www.cnblogs.com/yqgAKIOI/p/10485252.html
Copyright © 2020-2023  润新知