题目
给你一个序列a,长度为n,有m次操作,每次询问一个区间是否可以选出两个数它们的差为x,或者询问一个区间是否可以选出两个数它们的和为x,或者询问一个区间是否可以选出两个数它们的乘积为x ,这三个操作分别为操作1,2,3
题解
这题用莫队和bitset和卡常
莫队的时间O(
nn√
)
bitset时间除以64
总时间O(玄学???)
所以要卡常
1.读入优化
2.函数都要加inline(效果明显)
3.printf()用puts()代替
4.bitset.count()用bitset.any()代替(效果明显)
n=10^5时可以跑进1s
ac代码
#include<cstdio>
#include<algorithm>
#include<bitset>
#define N 100010
#define MX 100000
#define B 320
using namespace std;
inline int rd(){
char c;
int x=0,y=1;
while((c=getchar())<'0'||c>'9')if(c=='-')y=-1;
while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
return x*y;
}
struct Que{
int o,p,q,v,id;
}c[N];
bitset<N>f,g;
int b[N],v[N],n,m,ans[N],a[N],l,r;
inline bool cmp(Que p,Que q){
if(b[p.p]==b[q.p])return p.q<q.q;
return b[p.p]<b[q.p];
}
inline void Insert(int x){
if(++v[a[x]]==1){
f.set(a[x]);
g.set(MX-a[x]);
}
}
inline void Delete(int x){
if(--v[a[x]]==0){
f.reset(a[x]);
g.reset(MX-a[x]);
}
}
inline bool Solve(int o,int x){
if(o==1)return (f&(f<<x)).any();
if(o==2)return (g&(f<<(MX-x))).any();
for(int i=1;i<=B;i++)if(x%i==0&&v[i]&&v[x/i])return 1;
return 0;
}
int main(){
freopen("data.txt","r",stdin);
n=rd(),m=rd();
for(int i=1;i<=n;i++)a[i]=rd();
for(int i=1;i<=n;i++)b[i]=(i-1)/B+1;
for(int i=1;i<=m;i++){
c[i].o=rd(),c[i].p=rd(),c[i].q=rd(),c[i].v=rd();
c[i].id=i;
}
sort(c+1,c+m+1,cmp);
l=c[1].p; r=c[1].p-1;
for(int i=1;i<=m;i++){
while(l<c[i].p)Delete(l++);
while(l>c[i].p)Insert(--l);
while(r<c[i].q)Insert(++r);
while(r>c[i].q)Delete(r--);
ans[c[i].id]=Solve(c[i].o,c[i].v);
}
for(int i=1;i<=m;i++)if(ans[i])puts("hana");
else puts("bi");
}