And Reachability(DP)

6 篇文章 0 订阅

传送门

Toad Pimple has an array of integers a1,a2,…,ana1,a2,…,an.

We say that yy is reachable from xx if x<yx<y and there exists an integer array pp such that x=p1<p2<…<pk=yx=p1<p2<…<pk=y, and api&api+1>0api&api+1>0 for all integers ii such that 1≤i<k1≤i<k.

Here && denotes the bitwise AND operation.

You are given qq pairs of indices, check reachability for each of them.

Input

The first line contains two integers nn and qq (2≤n≤3000002≤n≤300000, 1≤q≤3000001≤q≤300000) — the number of integers in the array and the number of queries you need to answer.

The second line contains nn space-separated integers a1,a2,…,ana1,a2,…,an (0≤ai≤3000000≤ai≤300000) — the given array.

The next qq lines contain two integers each. The ii-th of them contains two space-separated integers xixi and yiyi (1≤xi<yi≤n1≤xi<yi≤n). You need to check if yiyi is reachable from xixi.

Output

Output qq lines. In the ii-th of them print "Shi" if yiyi is reachable from xixi, otherwise, print "Fou".

Example

input

Copy

5 3
1 3 0 2 1
1 3
2 4
1 4

output

Copy

Fou
Shi
Shi

Note

In the first example, a3=0a3=0. You can't reach it, because AND with it is always zero. a2&a4>0a2&a4>0, so 44 is reachable from 22, and to go from 11 to 44 you can use p=[1,2,4]p=[1,2,4].

题意:给你一个序列,q次询问,每次询问给出l和r,问你是否可以从l到r中选出一个序列,选出的序列值对应原序列的下标,使得相邻的两个值AND大于0

题解:要使AND不为0,就会在相同位置都出现1,找出当前值的二进制为1时,右边最近的二进制同为1的值,如果这个值的下标是小于等于右端点,则代表是可行方案,否则不是,由于是一个序列所以如果两个值AND不为0,那么左边的位置就会被右边可以到的位置更新,记录当前位为1时,最小的下标,如果跑到当前位置的数的二进制同为1就可以将其调出更新,在把当前位为1的最小位置更新掉;

AC代码:

#include<stdio.h>
#include<vector>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<queue>
#define ll long long
using namespace std;
const int maxn=3e5+5;
//const ll inf=9223372036854775800;
//const int inf=1e9;
//const int mod=1e9+7;
int dp[maxn][21],xi[maxn];
int num[21];
void get(int k){
    for(int a=0;a<=20;a++){
        if((xi[k]>>a)&1){
            dp[k][a]=k;
            if(num[a]){
                for(int b=0;b<=20;b++)
                dp[k][b]=min(dp[k][b],dp[num[a]][b]);
            }
            num[a]=k;
        }
    }
}
int main( ){
    int n,m;
    memset(num,0,sizeof(num));
    scanf("%d %d",&n,&m);
    for(int a=1;a<=n;a++){
        scanf("%d",&xi[a]);
        for(int b=0;b<=20;b++)
            dp[a][b]=maxn;
    }
    for(int a=n;a>=1;a--)
        get(a);
    int l,r;
    while(m--){
        scanf("%d %d",&l,&r);
        bool judge=false;
        for(int a=0;a<=20;a++){
            if(((xi[r]>>a)&1)&&dp[l][a]<=r){
                judge=true;
                break;
            }
        }
        if(!judge)
            printf("Fou\n");
        else
            printf("Shi\n");
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值