USACO Snow boots
洛谷链接
各位网友们用的都是并查集和双向链表这些高端操作,显然这对于我这种才学一年的初中蒟蒻来说是几乎想不到。这里献上一种特别无脑的解法。时间复杂度
O
(
n
l
o
g
2
n
+
q
)
O(nlog_2n+q)
O(nlog2n+q)(尽管它的常数很大) 。
我们对于每一块砖进行排序,dis数组来表示步长为i是最少要承受力为dis[i]的靴子,显然的只要知道每一个dis[i]的值,就可以
O
(
1
)
O(1)
O(1)得回答每一个问题。剩下啦的就只有模拟这个思路了。由于我比较菜所以只会用stl来实现这个过程了。
#include<cstdio>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <algorithm>
#define N 100005
using namespace std;
inline char get(){
const int TOP=1000000;
static char T[TOP],*x=T,*y=T;
return x==y&&(y=(x=T)+fread(T,1,TOP,stdin),x==y)?EOF:*x++;
}
inline int read (){
register int num,sign=1;register char c;
while (((c=get())<'0'||c>'9')&&c!='-');c=='-'?num=sign=0:num=c-48;
while ((c=get())>='0'&&c<='9')num=(num<<3)+(num<<1)+(c-48);
return sign?num:-num;
}
set<int>tr;//有哪些砖被计算
map<int,int>hash;//当前的可行步长,显然我们要的是最大的步长
struct node{
int data,id;
bool operator <(const node &x)const{
return data<x.data;
}
}A[N];
int n,q,x,y;
int dis[N];
set<int>::iterator l,r;
map<int,int>::iterator it;
int main(){
memset(dis,0x7f,sizeof(dis));
n=read();q=read();
for(int i=1;i<=n;++i){A[i].data=read();A[i].id=i;}
sort(A+2,A+n);
hash[n-1]++;tr.insert(1);tr.insert(n);
for(int i=2,j=2;i<n;i=j){
while(A[j].data<=A[i].data&&j<n){
l=r=tr.upper_bound(A[j].id);--l;
if(!(--hash[*r-*l])){hash.erase(*r-*l);}
hash[A[j].id-*l]++;hash[*r-A[j].id]++;
tr.insert(A[j++].id);
}
it=hash.end();--it;
dis[it->first]=min(dis[it->first],A[i].data);
}
dis[1]=A[n-1].data;dis[n-1]=0;
for(int i=2;i<n;++i)dis[i]=min(dis[i],dis[i-1]);//步长更小的答案显然可以更新步长较大的答案
while(q--){
x=read();y=read();
if(dis[y]<=x)printf("1\n");else printf("0\n");//O(1)的查询
}
}