zoukankan      html  css  js  c++  java
  • [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 ;
    }
    
  • 相关阅读:
    jQuery 源码解析(二十四) DOM操作模块 包裹元素 详解
    jQuery 源码解析(二十三) DOM操作模块 替换元素 详解
    jQuery 源码解析(二十二) DOM操作模块 复制元素 详解
    jQuery 源码分析(二十一) DOM操作模块 删除元素 详解
    jQuery 源码分析(二十) DOM操作模块 插入元素 详解
    jQuery 源码分析(十九) DOM遍历模块详解
    python 简单工厂模式
    python 爬虫-协程 采集博客园
    vue 自定义image组件
    微信小程序 image组件坑
  • 原文地址:https://www.cnblogs.com/beretty/p/10760731.html
Copyright © 2011-2022 走看看