[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)\)

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

代码

/*
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\n") ;
        else printf("NO\n") ;
    }
    return 0 ;
}
扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄