提高培优Day15T4

题目id:15724

题意

给定 n 个点,从左到右按顺序排成一行。连接第 i 个点和第 i+1 个点无向边,需要拥有类型为 C_i 的钥匙。到达第 i 个点可以得到 B_i 把钥匙,分别为 A[i][1],A[i][2],\dots,A[i][B_i]Q 个询问回答能否从起始点 X_i 到结束点 Y_i ,能则输出 YES 不能则输出 NO
其中 2≤N≤5×10^5,1≤Q≤5×10^5

思路

观察到 Q 很大,所以可以离线做,对于每个点 X_i 求出可达区间 [L_i,R_i]
考虑可达区间扩展:
\quad 对每个点 i 求出 bef_{c[i]}nxt_{c[i]} 分别表示在点 i 前面或后面,距离点 i 最近的拥有类型 C_i 钥匙的点位置

  • 当前区间为 [L_i,R_i] 时 若 L_i \leq nxt_{c[L_i-1]} \leq R_i 则代表可以扩展到 [L_i-1,R_i]

  • 当前区间为 [L_i,R_i] 时 若 L_i \leq bef_{c[R_i]} \leq R_i 则代表可以扩展到 [L_i,R_i+1]

但是发现若当前点 i 能够到达点 j 那么,区间 [L_j,R_j] 内的点,点 i 都可达所以每扩展到一个点让 L_i=min(L_i,L_j) \quad R_i=max(R_i,R_j)

用递归求解使每个点只用扩展一次跑的较快

code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N=5e5+100;
int c[N],n,B[N];
int L[N],R[N],bef[N],nxt[N],rem[N],q,vis[N];
vector<int>A[N];
void dfsf(int pos){
	if(vis[pos])return;
	vis[pos]=1;
	int flag=1;
	while(flag){
        flag=0;
        while(L[pos]-1>=1&&nxt[L[pos]-1]>=L[pos]&&nxt[L[pos]-1]<=R[pos]){
            dfsf(L[pos]-1);
			flag=1;L[pos]=min(L[L[pos]-1],L[pos]);
            R[pos]=max(R[L[pos]-1],R[pos]);
        }
        while(R[pos]+1<=n&&bef[R[pos]]>=L[pos]&&bef[R[pos]]<=R[pos]){
        	dfsf(R[pos]+1);
			flag=1;L[pos]=min(L[R[pos]+1],L[pos]);
            R[pos]=max(R[pos],R[R[pos]+1]);
        }
    }
    return;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<n;i++)scanf("%d",&c[i]);
    for(int i=1;i<=n;i++){
        scanf("%d",&B[i]);
        for(int j=1;j<=B[i];j++){
            int x;
            scanf("%d",&x);
            A[i].push_back(x);
            rem[x]=i;
        }
        bef[i]=rem[c[i]];
    }
    for(int i=1;i<=n;i++)rem[i]=n+1;
    for(int i=n;i>=1;i--){
        for(int j=0;j<B[i];j++)
            rem[A[i][j]]=i;
        nxt[i-1]=rem[c[i-1]];L[i]=R[i]=i;
    }
    for(int i=1;i<=n;i++)
    	if(!vis[i])dfsf(i); 
    scanf("%d",&q);
    for(int i=1;i<=q;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        if(y>=L[x]&&y<=R[x])printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

双倍经验

洛谷 AT_joisc2017_h 細長い屋敷 (Long Mansion)

2 个赞

6666

1 个赞

膜拜%%%

1 个赞