看了官方给的提解后恍然大悟,不过其实没必要用凸包,只要枚举即可。
首先想象0,1的字串都各只有一串的情况,则图形为一个完整的矩形。当字串增加,就是多个矩形的叠加。
因此只扫一次是明显不够的,要以每一个0串为起始串枚举下边界,以每一个1串为起始枚举上边界。
但是这样得到的两串数对(x,y)是冗余的,因此需要对得到的数对进行筛选,精简。
即找到如题解中所示的红点,以及绿点这些关键点。(蓝点是没必要去找的,蓝点是两个红点或绿点的交点处的点)
求红点的代码如下:(参考博客 http://blog.csdn.net/techmonster/article/details/52000284)
sort(lowp,lowp+cl);
n = 0;
for(int i = 0,j; i < cl; i = j) {
//找边界点(红点)
for(j = i; j < cl && lowp[j].first == lowp[i].first; ++j); //从i开始,到cl为止的点,如果x坐标相等,j++,越过横坐标相同的点(已排序)
while(n > 0 && lowp[n-1].second >= lowp[i].second) --n; //如果纵坐标减小,则更新边界点
lowp[n++] = lowp[i];
}
cl = n;
找到红点及绿点后,只要对点的边界二分搜索即可,在图形范围内则为1,否则为0。
完整代码:
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
using namespace std;
#define MS(x,y) memset(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define MAXN 100005
typedef long long LL;
const int N = (1e6)+10, M = 0, Z = 1e9 + 7, ms63 = 0x3f3f3f3f;
int n,m,org[1010];
pair<int ,int>lowp[N],upp[N];
char ans[MAXN*5];
void solve() {
scanf("%d%d",&n,&m);
for(int i = 0; i < n; ++i) scanf("%d",&org[i]); //org 储存0,1串
int x,y,cl = 0,cu = 0;
for(int i = 0; i < n; ++i) {
//暴力枚举所有边界
x=y=0;
for(int j = i; j < n; ++j) {
if(j%2 == 0) x+=org[j];
else y+=org[j];
if((i%2 == 0 && j%2 == 0) ) lowp[cl++] = MP(x,y);
if((i%2 == 1 && j%2 == 1) ) upp[cu++] = MP(x,y);
}
}
sort(lowp,lowp+cl);
n = 0;
// for(int i=0; i<cl; i++) cout<<i<<" "<<lowp[i].first<<" "<<lowp[i].second<<endl;
for(int i = 0,j; i < cl; i = j) {
//找边界点(红点)
for(j = i; j < cl && lowp[j].first == lowp[i].first; ++j); //从i开始,到cl为止的点,如果x坐标相等,j++,越过横坐标相同的点(已排序)
while(n > 0 && lowp[n-1].second >= lowp[i].second) --n; //如果纵坐标减小,则更新边界点
lowp[n++] = lowp[i];
}
cl = n;
//for(int i=0;i<cl;i++) cout<<"d"<<i<<" "<<lowp[i].first<<" "<<lowp[i].second<<endl;
sort(upp,upp+cu);
n = 0;
for(int i = 0,j; i < cu; i = j) {
for(j = i; j < cu && upp[j].first == upp[i].first; ++j);
if(!n || upp[j-1].second > upp[n-1].second) upp[n++] = upp[j-1];
}
cu = n;
//for(int i=0;i<cu;i++) cout<<"u"<<i<<" "<<upp[i].first<<" "<<upp[i].second<<endl;
int a,b,low,up;
for(int i = 0; i < m; ++i) {
scanf("%d%d",&a,&b);
low = lower_bound(lowp,lowp+cl,MP(a,-ms63))-lowp;
up = lower_bound(upp,upp+cu,MP(a,ms63))-upp;
if(low < cl&&up<=cu&& b >= lowp[low].second && b <= upp[up-1].second) ans[i] = '1';
else ans[i] = '0';
}
ans[m] = 0;
puts(ans);
}
int main() {
// freopen("in.txt","r",stdin);
int T;
scanf("%d",&T);
while(T--)solve();
return 0;
}