• CF1168C And Reachability


    CF1168C And Reachability

    洛谷CF1168C And Reachability

    题目大意

    有一个数组 a 1 , a 2 , ⋯   , a n a_1,a_2,\cdots,a_n a1,a2,,an,我们称 x x x y y y可达当且仅当:

    • x < y xx<y
    • 存在一个数组 p p p,其中 x = p 1 < p 2 < ⋯ < p k = y x=p_1x=p1<p2<<pk=y,且对于任意 1 ≤ i < k 1\leq i1i<k,满足 a p i & a p i + 1 > 0 a_{p_i}\& a_{p_i+1}>0 api&api+1>0

    q q q组询问,第 i i i组询问给出 x i x_i xi y i y_i yi,求它们是否可达。如果可达,输出 S h i Shi Shi;否则,输出 F o u Fou Fou

    1 ≤ n ≤ 3 × 1 0 5 , 1 ≤ q ≤ 3 × 1 0 5 , x i < y i 1\leq n\leq 3\times 10^5,1\leq q\leq 3\times 10^5,x_i1n3×105,1q3×105,xi<yi


    题解

    首先,如果 x x x y y y可达, y y y z z z可达,则 x x x z z z可达。

    对于一个点 i i i,如果 a i & 2 k > 0 a_i\& 2^k>0 ai&2k>0,则对于所有 j > i j>i j>i a j & 2 k > 0 a_j\& 2^k>0 aj&2k>0 i i i j j j都是可达的。

    w i , k w_{i,k} wi,k表示 i i i可达的最小的 j j j(这里,我们定义当 a i > 0 a_i>0 ai>0时, i i i i i i是可达的),那么,对于所有 j > i j>i j>i,只要满足存在一个 k k k使得 a j & 2 k > 0 a_j\& 2^k>0 aj&2k>0 w i , k ≤ j w_{i,k}\leq j wi,kj,则 i i i j j j可达。

    那如何求 w i , k w_{i,k} wi,k呢?对于每个 w i , k w_{i,k} wi,k,我们只需求出满足 j > i j>i j>i a j & 2 k > 0 a_j\&2^k>0 aj&2k>0的最小的 j j j,对于每个 0 ≤ t ≤ log ⁡ n 0\leq t\leq \log n 0tlogn,都令 w i , k = min ⁡ ( w i , k , w j , k ) w_{i,k}=\min(w_{i,k},w_{j,k}) wi,k=min(wi,k,wj,k)

    考虑 w i , k w_{i,k} wi,k的初始值。如果 a i & 2 k > 0 a_i\&2^k>0 ai&2k>0 w i , k = i w_{i,k}=i wi,k=i;否则, w i , k = n + 1 w_{i,k}=n+1 wi,k=n+1

    求出 w i , k w_{i,k} wi,k之后,对于每组 x , y x,y x,y,如果存在一个 k k k使得 a y & 2 k > 0 a_y\&2^k>0 ay&2k>0 w x , k ≤ y w_{x,k}\leq y wx,ky,输出 S h i Shi Shi;否则,输出 F o u Fou Fou

    时间复杂度为 O ( n log ⁡ 2 n ) O(n\log^2 n) O(nlog2n)

    code

    #include
    using namespace std;
    int n,q,x,y,fl,a[300005],lst[20],w[300005][20];
    int main()
    {
    //	freopen("and.in","r",stdin);
    //	freopen("and.out","w",stdout);
    	scanf("%d%d",&n,&q);
    	for(int i=1;i<=n;i++){	
    		scanf("%d",&a[i]);
    		for(int j=0;j<=19;j++){
    			if((a[i]>>j)&1) w[i][j]=i;
    			else w[i][j]=n+1;
    		}
    	}
    	for(int i=n;i>=1;i--){
    		for(int j=0;j<=19;j++){
    			if(!((a[i]>>j)&1)) continue;
    			if(lst[j])
    			for(int k=0;k<=19;k++){
    				w[i][k]=min(w[i][k],w[lst[j]][k]);
    			}
    			lst[j]=i;
    		}
    	}
    	while(q--){
    		scanf("%d%d",&x,&y);
    		fl=0;
    		for(int i=0;i<=19;i++){
    			if(((a[y]>>i)&1)&&w[x][i]<=y) fl=1;
    		}
    		if(fl) printf("Shi\n");
    		else printf("Fou\n");
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
  • 相关阅读:
    垃圾回收 -标记清除算法
    使用Minio Clinet进行Minio的数据迁移
    Java中HashMap之replace()方法具有什么功能呢?
    Ps:选择高光阴影中间调的方法
    MySQL5.7读写分离
    ThreeJS-3D教学九-line的绘制
    deepFm系列
    越早越好,突破职业瓶颈,2023年考PMP项目管理有何好处?
    【Unity细节】如何调节标签图标的大小(select icon)—标签图标太大遮住了物体
    [数据结构C++实现]二叉搜索树
  • 原文地址:https://blog.csdn.net/tanjunming2020/article/details/133869505