Ynoi2017 由乃的玉米田
Link
开一个桶记录每个数字出现过多少次,同时用bitset维护\(x\)是否出现过。
那么查询是否有两个数的差为\(x\)就是把bitset右移\(x\)位然后与自己,如果有位置为\(1\)那么就说明存在。
查询是否有两个数的和为\(x\)也可以类似地做,多开一个bitset维护\(10^5-x\)是否出现过。
查询是否有两个数的积为\(x\)可以直接枚举因数查询,注意特判\(x=0\)的情况。
最后是查询是否有两个数的商为\(x\),首先特判\(x=0\)的情况,对于\(x\ge64\)的数据,我们可以暴力枚举判断。
对于\(1\le x<64\)的,我们把所有\(x\)相同询问的放一起并按左端点降序排序,用树状数组维护一下以每个点为左端点的最左右端点就好了。
时间复杂度是\(O(\frac{n^2}{64}+n\sqrt n+64n\log n)\)。
(实际上除法那里最优的分治边界应该是\(\sqrt{\frac n{\log n}}\),这样复杂度就是\(O(\frac{n^2}{64}+n\sqrt{n\log n})\),不过\(64\)也差不多)
#pragma GCC optimize(3)
#include<cmath>
#include<cstdio>
#include<cctype>
#include<bitset>
#include<cstring>
#include<algorithm>
namespace IO
{
char ibuf[(1<<21)+1],*iS,*iT;
char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
int read(){int x=0,c=Get();while(!isdigit(c))c=Get();while(isdigit(c))x=x*10+c-48,c=Get();return x;}
}using IO::read;
using std::sort;
using std::bitset;
int min(int a,int b){return a<b? a:b;}
const int N=100007,U=100000,inf=0x3f3f3f3f;
bitset<N>S,T;
int n,m,bel[N],t[N],pos[N],a[N],ans[N];
struct node{int o,l,r,x,id;}q[N],p[N];
int operator<(const node&a,const node&b){return bel[a.l]==bel[b.l]? a.r<b.r:a.l<b.l;}
void add(int x){if(++t[x]==1)S[x]=T[U-x]=1;}
void del(int x){if(!--t[x])S[x]=T[U-x]=0;}
int askmul(int x){if(!x)return S[0];for(int i=1;i*i<=x;++i)if(!(x%i)&&S[i]&&S[x/i])return 1;return 0;}
int askdiv(int x){if(!x)return S[0]&&S.count()>1;for(int i=1,j=x;j<=U;++i,j+=x)if(S[i]&&S[j])return 1;return 0;}
void update(int p,int v){for(;p<=n;p+=p&-p)t[p]=min(t[p],v);}
int query(int p){int r=inf;for(;p;p^=p&-p)r=min(r,t[p]);return r;}
int main()
{
n=read(),m=read();int c=0,B=sqrt(n)+rand()%5;
for(int i=1;i<=n;++i) a[i]=read(),bel[i]=(i-1)/B+1;
for(int i=1;i<=m;++i) q[i]={read(),read(),read(),read(),i};
sort(q+1,q+m+1);
for(int i=1,L=1,R=0;i<=m;++i)
{
int l=q[i].l,r=q[i].r,x=q[i].x;
if(q[i].o==4&&q[i].x<64&&q[i].x) {p[++c]=q[i];continue;}
while(l<L) add(a[--L]);
while(R<r) add(a[++R]);
while(L<l) del(a[L++]);
while(r<R) del(a[R--]);
if(q[i].o==1) ans[q[i].id]=(S&S<<x).any();
else if(q[i].o==2) ans[q[i].id]=(S&T>>(U-x)).any();
else if(q[i].o==3) ans[q[i].id]=askmul(x);
else ans[q[i].id]=askdiv(x);
}
sort(p+1,p+c+1,[](const node&a,const node&b){return a.x<b.x||(a.x==b.x&&a.l>b.l);});
for(int l=1,r;l<=c;l=r+1)
{
for(r=l;p[r+1].x==p[l].x&&r<c;++r);
memset(t,0x3f,sizeof t),memset(pos,0x3f,sizeof pos);
for(int i=l,j=n;i<=r;++i)
{
for(;j>=p[i].l;--j)
{
pos[a[j]]=j;
if(1ll*a[j]*p[l].x<=U) update(j,pos[a[j]*p[l].x]);
if(!(a[j]%p[l].x)) update(j,pos[a[j]/p[l].x]);
}
ans[p[i].id]=p[i].l>p[i].r? 0:query(p[i].r)<=p[i].r;
}
}
for(int i=1;i<=m;++i) puts(ans[i]? "yuno":"yumi");
}