And Reachability - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
给定一个长度为 n n n 的数组 a a a 。
你可以选择一个长度为 k k k 的数组 p p p
p 1 = x , p k = y p_1 = x , p _k = y p1=x,pk=y
当 x < y x
现在给你 q q q 组询问,每个询问问你 x , y x , y x,y 是否可以到达
d p dp dp
设 c i , j c_{i , j} ci,j 为二进制下的 a i a_i ai 的第 j j j 位是否为 1 1 1
设 g i , j g_{i , j} gi,j 为 [ 1 , i − 1 ] [1,{i- 1}] [1,i−1] 中第 j j j 位为 1 1 1 且离 i i i 最近的点
那么
g i , j = ( c i − 1 , j = 1 ) ? i − 1 : g i − 1 , j g_{i , j} = (c_{i - 1 , j} = 1) ? i - 1 : g_{i - 1 , j} gi,j=(ci−1,j=1)?i−1:gi−1,j
设 f i , j f_{i , j} fi,j 为 [ 1 , i − 1 ] [1 , i -1] [1,i−1] 中第 j j j 位为 1 1 1 且能够到达 i i i 的最近的一个点
需要中转站
f i , j = m a x ( f i , j , f g i , k , j ) ( c i , k = 1 ) f_{i , j} = max (f_{i , j} , f_{g_{i , k} , j}) (c_{i , k} = 1) fi,j=max(fi,j,fgi,k,j)(ci,k=1)
不需要中转站
f i , j = m a x ( f i , j , f i , k ) ( c i , k = = 1 a n d c g i , k , j = 1 ) f_{i , j} = max (f_{i , j} , f_{i , k}) (c_{i , k} == 1 \ and \ c_{g_{i , k} , j} = 1 ) fi,j=max(fi,j,fi,k)(ci,k==1 and cgi,k,j=1)
#include
#define fu(x , y , z) for(int x = y ; x <= z ; x ++)
#define fd(x , y , z) for(int x = y ; x >= z ; x --)
using namespace std;
const int N = 3e5 + 5;
int n , q;
int a[N] , f[N][25] , g[N][25] , c[N][25];
int read () {
int val = 0;
char ch = getchar ();
while (ch > '9' || ch < '0') ch = getchar ();
while (ch >= '0' && ch <= '9') {
val = val * 10 + (ch - '0');
ch = getchar();
}
return val;
}
void pre (int i , int x) {
fu (j , 1 , 20) {
if (x & 1) c[i][j] = 1;
x >>= 1;
}
}
int main () {
freopen ("and.in" , "r" , stdin);
freopen ("and.out" , "w" , stdout);
n = read () , q = read ();
fu (i , 1 , n) {
a[i] = read ();
pre (i , a[i]);
}
fu (i , 1 , n) {
fu (j , 1 , 20) {
if (c[i - 1][j]) g[i][j] = i - 1;
else g[i][j] = g[i - 1][j];
}
}
fu (i , 1 , n) {
fu (j , 1 , 20) {
fu (k , 1 , 20) {
if (!c[i][k]) continue;
int x = g[i][k];
if (c[x][j]) f[i][j] = max (f[i][j] , x);
else f[i][j] = max (f[i][j] , f[x][j]);
}
}
}
int l , r , flg = 0;
while (q --) {
flg = 0;
scanf ("%d%d" , &l , &r);
fu (i , 1 , 20) {
if (c[l][i] && f[r][i] >= l) {
puts ("Shi");
flg = 1;
break;
}
}
if (flg) continue;
puts ("Fou");
}
return 0;
}