洛谷 P3674 小清新人渣的本愿 [莫队 bitset]
题意:
给你一个序列a,长度为n,有Q次操作,每次询问一个区间是否可以选出两个数它们的差为x,或者询问一个区间是否可以选出两个数它们的和为x,或者询问一个区间是否可以选出两个数它们的乘积为x ,这三个操作分别为操作1,2,3
题面太强啦!!!
感觉就是莫队,想了一下分块不好搞更坚定了莫队的信念
$a-b=x$,$a=x+b$,放在权值数组上就是b右移x位,$bitset$大法好
加法同理
乘法,总共就$\sqrt{N}$个约数....
感觉复杂度$O(\frac{N^2}{64} + N\sqrt{N})$不靠谱结果竟然A了...
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <bitset> using namespace std; typedef long long ll; const int N=1e5+5, M=2e5+5; inline ll read(){ char c=getchar();ll x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();} return x*f; } int n, Q, a[N], op, l, r, x; int block, m, pos[N]; struct meow{ int l, r, x, type, qid; bool operator <(const meow &a) const {return pos[l]==pos[a.l] ? r<a.r : pos[l]<pos[a.l];} }q[N]; int ans[N]; struct Meow{ bitset<M> a, b, c; int cou[N]; inline void add(int v) { cou[v]++; if(cou[v]==1) a[v]=1, b[v+N]=1, c[-v+N]=1; } inline void del(int v) { cou[v]--; if(cou[v]==0) a[v]=0, b[v+N]=0, c[-v+N]=0; } int Que(int type, int x) { //printf("Que %d %d\n",type,x); int ans=0; if(type==1) { if( (a & (a<<x)).any() ) ans=1; }else if(type==2) { if( (b & (c<<x)).any() ) ans=1; }else { int m=sqrt(x); for(int i=1; i<=m; i++) if(x%i == 0) if(cou[i] && cou[x/i]) {ans=1; break;} } return ans; } }A; void modui(){ int l=1, r=0; for(int i=1; i<=Q; i++){ while(r<q[i].r) r++, A.add(a[r]); while(r>q[i].r) A.del(a[r]), r--; while(l<q[i].l) A.del(a[l]), l++; while(l>q[i].l) l--, A.add(a[l]); ans[q[i].qid]= A.Que(q[i].type, q[i].x); } } int main(){ // freopen("in","r",stdin); n=read(); Q=read(); block=sqrt(n); m=(n-1)/block+1; for(int i=1; i<=n; i++) a[i]=read(), pos[i]=(i-1)/block+1; for(int i=1; i<=Q; i++) op=read(), l=read(), r=read(), x=read(), q[i]=(meow){l, r, x, op, i}; sort(q+1, q+1+Q); modui(); for(int i=1; i<=Q; i++) puts(ans[i] ? "hana" : "bi"); }
Copyright:http://www.cnblogs.com/candy99/