给定 01 序列,每次询问是否存在连续区间使得 0 的个数为 ai , 1 的个数为 bi .
对于一个固定的 a ,可行的 b 是一个区间.如果我们把所有可行的 (a,b) 画在二维平面上,
可以观察到这个可行区域一定是连通的,且上下界有一些和 x 轴 y 轴平行的线段组成.于是我们需要求出这个区域的上下边界.对于上边界中在线段转折处的点,一定是一个从 1 开始, 以 1 结尾的序列长度,下边界的线段转折点处的点,一定是一个从 0 开始, 以 0 结尾的序列长度.
枚举连续的以 01…10 序列并排序,求下边界,枚举连续的 10…01 序列求上边界,这就求出了可行区域的上下边界.
这样对每一个询问 (a,b) 我们二分求出与 a 对应的 b 的可行范围,就可以判断了.
/****************************************\ * Author : ztx * Title : Helter Skelter * ALG : * CMT : * Time : \****************************************/
#include
#define Rep(i,l,r) for(i=(l);i<=(r);i++)
#define rep(i,l,r) for(i=(l);i< (r);i++)
#define Rev(i,r,l) for(i=(r);i>=(l);i--)
#define rev(i,r,l) for(i=(r);i> (l);i--)
typedef long long ll ;
typedef double lf ;
int CH , NEG ;
template <typename TP>inline void read(TP& ret) {
ret = NEG = 0 ; while (CH=getchar() , CH<'!') ;
if (CH == '-') NEG = true , CH = getchar() ;
while (ret = ret*10+CH-'0' , CH=getchar() , CH>'!') ;
if (NEG) ret = -ret ;
}
template <typename TP>inline void readc(TP& ret) {
while (ret=getchar() , ret<'!') ;
while (CH=getchar() , CH>'!') ;
}
template <typename TP>inline void reads(TP *ret) {
ret[0]=0;while (CH=getchar() , CH<'!') ;
while (ret[++ret[0]]=CH,CH=getchar(),CH>'!') ;
ret[ret[0]+1]=0;
}
#include
#define maxn 1010LL
#define maxt 1000010LL
#define infi 1000000010LL
struct node {
int a , b ;
bool operator < (const node&B) const {
if (a == B.a) return b < B.b ;
return a < B.a ;
}
} up[maxt] , down[maxt] , tmp ; int totd , totu ;
int a[maxn] , s0[maxn] , s1[maxn] ;
int main() {
int n , m , max0 , max1 , T , i , j , k , aa , bb ;
// #define READ
#ifdef READ
freopen(".in" ,"r",stdin ) ;
freopen(".out","w",stdout) ;
#endif
for (read(T) ; T --> 0 ; ) {
read(n) , read(m) ;
s0[0] = s1[0] = a[0] = a[n+1] = max0 = max1 = 0 ;
Rep (i,1,n) {
read(a[i]) ;
s0[i] = s0[i-1] , s1[i] = s1[i-1] ;
if (i&1) s0[i] += a[i] , max0 = std::max(max0,a[i]) ;
else s1[i] += a[i] , max1 = std::max(max1,a[i]);
}
totd = totu = 0 ;
for (k = 1 ; k <= n ; k += 2)
for (i = 1 ; j = i+k-1 , j <= n ; i += 2) {
down[++totd] = (node){s0[j]-s0[i-1],s1[j]-s1[i-1]} ;
up[++totu] = (node){s0[j]-s0[i-1],s1[j]-s1[i-1]+a[i-1]+a[j+1]} ;
}
up[++totu] = (node){0,max1} ;/// !!! !!! !!!
std::sort(down+1,down+totd+1) ;
std::sort(up+1,up+totu+1) ;
/// Get Down find a lowest rising path
k = totd ;
for (totd = 1 , i = 2 ; i <= k ; i ++ )
if (down[i].a != down[totd].a) {
while (totd && down[totd].b >= down[i].b) totd -- ;
down[++totd] = down[i] ;
}
down[++totd] = (node){infi,infi} ;
/// Get Up find a highest rising path
k = totu ;
for (totu = 1 , i = 2 ; i <= k ; i ++ )
if (up[i].a == up[totu].a) up[totu] = up[i] ;
else if (up[i].b > up[totu].b) up[++totu] = up[i] ;
up[++totu] = (node){infi,-1} ;
/// Answer
while (m -- ) {
read(aa) , read(bb) ;
if (!aa) { putchar((bb<=max1)+'0') ; continue ; }
if (!bb) { putchar((aa<=max0)+'0') ; continue ; }
if (aa > s0[n] || bb > s1[n]) { putchar('0') ; continue ; }
i = std::upper_bound(down+1,down+totd+1,(node){aa,-1})-down ;
if (down[i].b > bb) { putchar('0') ; continue ; }
i = std::upper_bound(up+1,up+totu+1,(node){aa,infi})-up ;
if (up[i-1].b < bb) { putchar('0') ; continue ; }
putchar('1') ;
}
puts("") ;
}
#ifdef READ
fclose(stdin) ; fclose(stdout) ;
#else
getchar() ; getchar() ;
#endif
return 0 ;
}