题面:
题意:
给定一个序列,每次查询一个区间的三种情况:(1)是否有两数之差为X(2)是否有两数之和为X(3)是否有两数之积为X
分析:
容易想到离线后莫队,考虑该怎么维护答案;对于①操作:A - B = X ----> A = B + X,对于一个集合都加上X,用bitset维护区间的数的集合S,只需要判断 S&(S<<X)即可,对于②:A + B = X ----> A = -B + X,但bitset不能维护负数,索性再维护(N-B)的集合T,那么有:A - (N-B) = X - N ---> A+(N-X) = (N-B),只需判断(S<<(N-X))&T 即可;对于三操作,直接暴力分解因子判断即可
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+15;
struct node{
int op,l,r,x,pos;
}p[maxn];
int n,m,block,a[maxn],num[maxn],ans[maxn];
bool cmp(node a,node b){
return a.l/block==b.l/block?a.r<b.r:a.l<b.l;
}
bitset<maxn> bs1,bs2,s;
inline void add(int x){
bs1[a[x]] = 1;
bs2[maxn-1-a[x]] = 1;
num[a[x]]++;
}
inline void del(int x){
if(--num[a[x]]==0){
bs1[a[x]] = 0;
bs2[maxn-1-a[x]] = 0;
}
}
int main(){
cin >> n >> m;
block = sqrt(n*1.0);
for(int i = 1;i <= n; ++i) cin >> a[i];
for(int i = 0;i < m; ++i) cin>>p[i].op>>p[i].l>>p[i].r>>p[i].x,p[i].pos=i;
sort(p,p+m,cmp);
int L = 1,R = 0;
for(int i = 0;i < m; ++i){
while(R < p[i].r) ++R,add(R);
while(R > p[i].r) del(R),--R;
while(L < p[i].l) del(L),++L;
while(L > p[i].l) --L,add(L);
if(p[i].op == 1){
s = (bs1<<p[i].x)&bs1;
if(s.any()) ans[p[i].pos] = 1;
}
else if(p[i].op == 2){
s = (bs1<<(maxn-1-p[i].x))&bs2;
if(s.any()) ans[p[i].pos] = 1;
}
else{
for(int j = 1;j*j<=p[i].x; ++j){
if(p[i].x%j==0&&num[j]&&num[p[i].x/j]){
ans[p[i].pos] = 1;
break;
}
}
}
}
for(int i = 0;i < m; ++i){
if(ans[i]) puts("yuno");
else puts("yumi");
}
return 0;
}