题目大意:
给定若干个01区间,比如有a个连续的0,b个连续的1,c个连续的0,d个连续的1………………
这样的一一大堆数字。
然后问,是否存在这样一个区间[l,r]使得整个区间里0,和1的个数分别为A,B个。
比如00001111100011 这样会被写成4,5,3,2 (只不过为了优化读入时间而已)
然后可以选区间00[0011111000]11 这样,也就是可以切开连续的区间,选择一个区间。这个区间有5个0,5个1.
解法1:
扫描线法。
先离散化所有数字,因为最多有n个连续01串,所以我们可以得到有如下东西:
l,r,L,R 表示,有一个方案,可以得到 0的数量在[l,r]之间,1的数量在[L,R]之间。
其实可以通过穷举i<= j <=n,使得我们知道所有的上述{l,r,L,R}的数值。
对l,r进行扫描线算法(队友和我说这叫扫描线算法)。
在一条直线上,记录事件点.比如有直线[5,10],那么我们记录在5开始的时候,有直线进入,在10结束的时候,有直线退出。
那么,我们就可以扫描这一整条直线,得出在k时刻,当前有多少条(或者有没有)直线覆盖了这个点。
然后再记录一些事件,比如l=5,r=10,L=7,R=15的话
在扫描到5的时候,我们加入(线段树也好,树状数组也好)区间[L,R], 扫描到10的时候,拿走区间[L,R]。
同时,在扫描到5的时候,我们可以查询{A=5,B}的所有询问。 我们把询问按照A排序,然后就可以一边扫描,一边添加/删除线段,一边排序了。
这道题内存不算卡的太严格,但是想偷懒多用内存是不行的……
所以所有事件点并不能全部离散,只能离散询问的所有{A,B}
这样,当一条线段[l,r]添加进离散后的区间的话,就有一些细节要想清楚了……比如添加在哪里,删除在哪里,啥时候添加,啥时候删除……
#include <cstdio>
#include <ctime>
#include <vector>
#include <stack>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
#define pr(x) cout<<#x<<" = "<<x<<" "
#define prln(x) cout<<#x<<" = "<<x<<endl
const int maxn = 1e6+1000;
const int maxm = 5 * 1e5 + 100;
int w[1111];
int n, m;
//map<int, int>lisan;
struct question //记录每个询问,题目说有m次
{
int a, b,id;
}q[maxm];
bool operator < (question A, question B)
{
return A.a < B.a;
}
struct ls//离散
{
int lisan[maxn * 2];
int t;
void ins(int k)
{
++t;
lisan[t] =k;
}
void clear()
{
t=0;
}
void doit()
{
sort(lisan + 1, lisan + 1+ t);
if (t>=maxn*2)
{
int t;
while(1)
{
++t;
//cout<<"1"<<endl;
}
}
t = unique(lisan + 1, lisan + 1+ t) - (lisan + 1);
}
int get(int k) //查找k的下标
{
return lower_bound(lisan + 1, lisan + 1 + t, k) - (lisan);
}
int get2(int k) //查找比K大的下标
{
return upper_bound(lisan + 1, lisan + 1 + t, k) - (lisan);
}
}lisan;
struct qujian
{
int L,R,id;
}jin[maxn * 2], chu[maxn*2];
int qujianT;
int st[maxn * 2], ed[maxn * 2];
bool operator < (qujian A, qujian B)
{
return A.id < B.id;
}
void make(int l, int r, int L, int R)
{
//cout<<l<<" "<<r<<" "<<L<<" "<<R<<endl;
int a = lisan.get(l);
int b = lisan.get2(r);
//cout<<"#"<<b<<endl;
if (r < lisan.lisan[b])
{
--b;
}
if (a>b) return;
++qujianT;
// cout<<"# "<<a<<" ->"<<b<<" "<<r<<" "<<lisan.lisan[b]<<endl;
// if (r > lisan.lisan[b]) --b;
// cout<<a<<" ->"<<b<<endl;
++st[a];
++ed[b];
jin[qujianT]={L,R,a};
chu[qujianT]={L,R,b};
}
void init()
{
lisan.clear();
scanf("%d%d", &n, &m);
for (int i = 1; i <=n;++i)
{
scanf("%d", &w[i]);
}
for (int i = 1; i <= m; ++ i)
{
scanf("%d%d",&q[i].a, &q[i].b);
q[i].id=i;
lisan.ins(q[i].a);
lisan.ins(q[i].b);
}
lisan.ins(1e9+9);
lisan.ins(-1);
lisan.doit(); //离散化进行排序
memset(st,0,sizeof(st));
memset(ed,0,sizeof(ed));
qujianT=0;
for (int i = 1; i <= n; ++ i)
{
//奇数都是0,偶数都是1的
int l=0,r=0, L=0,R=0;
if (i&1) r= w[i];
else R = w[i];
make(l,r,L,R);
if (i==n) continue;
if (i&1)
{
R = w[i + 1];
}else r = w[i + 1];
make(l,r,L,R);
}
for (int i = 1; i <=n - 2 ; ++ i)
{
int l=0,r=0,L=0,R=0;
if (i&1) r=w[i], R=w[i + 1];
else R=w[i], r=w[i + 1];
for (int j = i + 2; j <=n; ++ j)
{
if (j&1)
{
L += w[j - 1], r += w[j];
}
else l += w[j - 1], R += w[j];
//qj[++qt]={l,r,L,R};
make(l,r,L,R);
}
}
sort(jin + 1, jin + 1 + qujianT);//进出的L,R区间,按照出现的位置排序
sort(chu + 1, chu + 1 + qujianT);
}
int s[maxn];
inline void ins(int k,int num)
{
for (;k<=lisan.t + 5;k += (k&-k))
{
s[k]+=num;
}
}
inline int ask(int k)
{
++k;
int ret=0;
for (;k>=1; k -= k&-k) ret+=s[k];
return ret;
}
inline void insert(int l, int r)
{
++l;
++r;
ins(l,1);
ins(r,-1);
}
inline void del(int l, int r)
{
++l;
++r;
ins(l, -1);
ins(r, 1);
}
int output[maxn];
void doit()
{
memset(s,0,sizeof(s));
sort(q + 1, q + 1 + m);
int wenti=1, now=0;//第几个问题了,现在有几个a
int jinT=1,chuT=1;
for (int i = 1; i<= lisan.t; ++ i)
{
now += st[i];
while (jinT <= qujianT && jin[jinT].id ==i)
{
int l , r;
l = lisan.get(jin[jinT].L);
r = lisan.get(jin[jinT].R + 1);
insert(l ,r);
++jinT;
}
while (wenti <= m && lisan.get(q[wenti].a)==i)
{
output[q[wenti].id] = now && ask(lisan.get(q[wenti].b)) ;
++wenti;
}
now -= ed[i];
while (chuT <= qujianT && chu[chuT].id == i)
{
int l , r ;
l = lisan.get(chu[chuT].L);
r = lisan.get(chu[chuT].R + 1);
del(l ,r);
++chuT;
}
}
for (int i = 1; i <= m; ++ i)
printf("%d", output[i]>=1);
printf("\n");
}
int main()
{
int T;
double st=clock();
scanf("%d", &T);
while (T--)
{
init();
doit();
}
//cout<<"程序运行时间为: "<< (clock()-st)/1000<<endl;
return 0;
}