• [HNOI/AHOI2018]游戏



    题解

    一个点的影响区间显然是一段连续的区间
    这样一个显然的(O(n^2))暴力就是我们可以将一个点向左右扩展,处理出从这个点出发能到达的左右端点(lp,rp)
    然后考虑怎么优化这个暴力
    首先如果我们从点(u)向左扩展到(l),并且这个(l)已经被扩展过
    那么我们就可以直接让(lp[u])变成(lp[l])
    所以我们如果能确定一个顺序使得更新到这个点的时候所有ta能更新的点已经被更新过的话这个复杂度就变得肥肠优秀了
    我们考虑每个门和钥匙((x,Key_x))
    如果钥匙在门的左边,那么显然门右边的点都过不了这个门
    那么我们就对这个门(x)连一条((x+1,x))
    表示反正右边的点过不了门,所以先处理门右边的部分,再处理门左边的部分
    反之就连((x,x+1))
    然后拓扑排序的时候当处理到这个点的时候ta能更新到的点都已经被更新了
    所以直接暴力更新就可以了
    然后注意如果两个屋子之间没有门就把他们缩起来
    复杂度(O(n+m))

    代码

    /*
    Key[i] <= i 钥匙在左门在右
      add_edge(i+1,i)
    Key[i] > i 钥匙在右门在左
      add_edge(i,i+1)
    
    */
    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    const int M = 1000005 ;
    using namespace std ;
    
    inline int read() {
    	char c = getchar() ; int x = 0 , w = 1 ;
    	while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
    	while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
    	return x*w ;
    }
    
    bool exist[M] ;
    int n , m , cnt , num ;
    int f[M] , idx[M] , Key[M] ;
    int d[M] , hea[M] , xp[M] , yp[M] , lp[M] , rp[M] ;
    struct E {
    	int nxt , to ;
    } edge[M] ;
    int find(int x) {
    	if(f[x] != x)
    		f[x] = find(f[x]) ;
    	return f[x] ;
    }
    inline void add_edge(int from , int to) {
    	edge[++num].nxt = hea[from] ;
    	edge[num].to = to ;
    	hea[from] = num ;
    }
    
    inline void topsort() {
    	queue < int > q ;
    	for(int i = 1 ; i <= cnt ; i ++) {
    		lp[i] = rp[i] = i ;
     		if(!d[i])
    			q.push(i) ;
    	}
    	while(!q.empty()) {
    		int u = q.front() ; q.pop() ;
    		bool suc = true ;
    		while(suc) {
    			suc = false ;
    			if(lp[u] > 1 && Key[lp[u] - 1] >= lp[u] && Key[lp[u] - 1] <= rp[u])
    				lp[u] = lp[lp[u] - 1] , suc = true ;
    			if(rp[u] < cnt && Key[rp[u]] <= rp[u] && Key[rp[u]] >= lp[u])
    				rp[u] = rp[rp[u] + 1] , suc = true ;
    		}
    		for(int i = hea[u] ; i ; i = edge[i].nxt) {
    			int v = edge[i].to ;
    			-- d[v] ;
    			if(!d[v])
    				q.push(v) ;
    		}
    	}
    }
    int main() {
    	n = read() ; m = read() ; int Case = read() ;
    	for(int i = 1 ; i <= n ; i ++)
    		f[i] = i ;
    	for(int i = 1 ; i <= m ; i ++) {
    		xp[i] = read() ; yp[i] = read() ;
    		exist[xp[i]] = true ;
    	}
    	for(int i = 1 ; i < n ; i ++) {
    		if(exist[i]) continue ;
    		int x = find(i) , y = find(i + 1) ;
    		if(x != y) f[y] = x ;
    	}
    	for(int i = 1 ; i <= n ; i ++) {
    		if(find(i) != find(i - 1)) ++ cnt ;
    		idx[i] = cnt ;
    	}
    	for(int i = 1 ; i <= m ; i ++)
    		Key[idx[xp[i]]] = idx[yp[i]] ;
    	for(int i = 1 ; i < cnt ; i ++) {
    		if(Key[i] <= i) {
    			add_edge(i + 1 , i) ;
    			++ d[i] ;
    		}
    		else {
    			add_edge(i , i + 1) ;
    			++ d[i + 1] ;
    		}
    	}
    	topsort() ;
    	int x , y ;
    	while(Case --) {
    		x = read() ; y = read() ;
    		if(idx[y] >= lp[idx[x]] && idx[y] <= rp[idx[x]])
    			printf("YES
    ") ;
    		else printf("NO
    ") ;
    	}
    	return 0 ;
    }
    
  • 相关阅读:
    女程序员发的一条微博
    【转】Android中JNI的使用方法
    【转】浏览器~加载,解析,渲染
    【转】PHP简单拦截器的实现
    【转】jQuery选择器总结
    【转】JS跨域(ajax跨域、iframe跨域)解决方法及原理详解(jsonp)
    【转】JSONP跨域的原理解析
    utuntu16.04安装tensorflow1.4-gpu
    Kaggle-Digit Recognizer
    python 常见细节知识点
  • 原文地址:https://www.cnblogs.com/beretty/p/10760731.html
Copyright © 2020-2023  润新知