题意:
分析:
弱化版 : 小清新人渣的本愿
分操作考虑:
-
加 or 减
本质就是查询区间内是否有一个数对,想了半天都没有想到有什么数据结构可以做,最后发现,竟然还有个 (bitset)
维护一个正着的 (bitset) 和一个反着的 (bitset) 就可以同时实现加减的操作
-
乘
最水的一个操作,(O(sqrt x))枚举因数 ,(bitset) 判断是否存在
-
除
可以转化成乘法,判断 (a,ax) 是否同时存在,当 (a,b) 很小的时候枚举倍数是 (O(m/a)) 的复杂度就不对了,但是我们发现对于值很小的时候,对于每一个询问,我们可以 (O(n)) 的扫一遍判断把每个值都存下来,一边扫一边判断它的倍数是否出现过
这样得到了两种做法,当 (x>sqrt{10000}) 时枚举倍数不超过 (O(sqrt{10000})) 次,当 (x<sqrt{100000}) 时这样的数不超过 (sqrt{100000}) 个,所以总复杂度不超过 (O(nsqrt m))
代码:
#include<bits/stdc++.h>
#define pii pair<int,int>
#define mk(x,y) make_pair(x,y)
#define lc rt<<1
#define rc rt<<1|1
#define pb push_back
#define fir first
#define sec second
#define inl inline
#define reg register
using namespace std;
namespace zzc
{
typedef long long ll;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
const int maxn = 1e5+5;
const int sqr = 325;
int n,m,blo,tot;
int v[maxn],cnt[maxn],lst[maxn],colst[maxn],ans[maxn];
vector<int> ql[sqr+5],qr[sqr+5],qi[sqr+5];
bitset<maxn> bs1,bs2;
struct que
{
int l,r,opt,x,id;
bool operator <(const que &b)const
{
return (l/blo)==(b.l/blo)?((l/blo)&1?r<b.r:r>b.r):l<b.l;
}
}q[maxn];
void ins(int x)
{
if(++cnt[x]==1) bs1[x]=1,bs2[100000-x]=1;
}
void del(int x)
{
if(--cnt[x]==0) bs1[x]=0,bs2[100000-x]=0;
}
bool query_mul(int x)
{
for(int i=1;i*i<=x;i++) if(x%i==0&&bs1[i]&&bs1[x/i]) return true;
return false;
}
bool query_dev(int x)
{
for(int i=1;i*x<=100000;i++) if(bs1[i]&&bs1[i*x]) return true;
return false;
}
void mo()
{
int l=1,r=0;
for(int i=1;i<=tot;i++)
{
while(l>q[i].l) ins(v[--l]);
while(r<q[i].r) ins(v[++r]);
while(l<q[i].l) del(v[l++]);
while(r>q[i].r) del(v[r--]);
if(q[i].opt==1) ans[q[i].id]=((bs1<<q[i].x)&bs1).any();
else if(q[i].opt==2) ans[q[i].id]=((bs1<<(100000-q[i].x))&bs2).any();
else if(q[i].opt==3) ans[q[i].id]=query_mul(q[i].x);
else ans[q[i].id]=query_dev(q[i].x);
}
}
void solve()
{
for(int x=1;x<=sqr;x++)
{
if(ql[x].empty()) continue;
int l=0;
for(int i=1;i<=n;i++)
{
int y=v[i];
lst[y]=i;
if(x*y<=100000) l=max(l,lst[x*y]);
if(y%x==0) l=max(l,lst[y/x]);
colst[i]=l;
}
for(int i=0,j=ql[x].size();i<j;i++) ans[qi[x][i]]=(ql[x][i]<=colst[qr[x][i]]);
memset(lst,0,sizeof(lst));
memset(colst,0,sizeof(colst));
}
}
void work()
{
int opt,l,r,c;
n=read();m=read();blo=n/sqrt(m);
for(int i=1;i<=n;i++) v[i]=read();
for(int i=1;i<=m;i++)
{
opt=read();l=read();r=read();c=read();
if(opt==4&&c<=sqr) ql[c].pb(l),qr[c].pb(r),qi[c].pb(i);
else
{
q[++tot].opt=opt;
q[tot].id=i;
q[tot].l=l;
q[tot].r=r;
q[tot].x=c;
}
}
sort(q+1,q+tot+1);
mo();
solve();
for(int i=1;i<=m;i++) if(ans[i]) puts("yuno");else puts("yumi");
}
}
int main()
{
zzc::work();
return 0;
}