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 ;
    }
    
  • 相关阅读:
    【郑轻邀请赛 G】密室逃脱
    【郑轻邀请赛 C】DOBRI
    【郑轻邀请赛 F】 Tmk吃汤饭
    【郑轻邀请赛 I】这里是天堂!
    【郑轻邀请赛 B】base64解密
    【郑轻邀请赛 A】tmk射气球
    【郑轻邀请赛 H】 维克兹的进制转换
    解决adb command not found以及sdk环境配置
    adb shell 命令详解,android, adb logcat
    Unexpected exception 'Cannot run program ... error=2, No such file or directory' ... adb'
  • 原文地址:https://www.cnblogs.com/beretty/p/10760731.html
Copyright © 2011-2022 走看看