#莫队,bitset#洛谷 3674 小清新人渣的本愿

题目


分析

只要做到\(O(n\sqrt{n})\)的时间复杂度就可以了
考虑莫队,首先乘号就是枚举\(x\)的约数\(d\)
判断\(d\)\(\frac{x}{d}\)是否同时出现,
再考虑差,怎样优化暴力,考虑bitset,将其左移\(x\)位,
再与原bitset按位与,若有公共的1即为是
那和怎么办,\(a+b=x\)那不就是\(a-(-b)=x\)吗,把\(-b\)扔进bitset就可以了
由于bitset里不能放负数所以要下标整体左移\(n\)


代码

#include <cstdio>
#include <cctype>
#include <bitset>
#include <algorithm>
#define rr register
using namespace std;
const int N=100011; bitset<N>uk,ku;
struct five{int opt,l,r,x,rk;}q[N];
int kuai[N],Sqrt[N],a[N],ans[N],n,Q,CNT[N];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
bool cmp(five a,five b){
    if (kuai[a.l]^kuai[b.l]) return a.l<b.l;
    if (kuai[a.r]^kuai[b.r]) return kuai[a.l]&1?a.r<b.r:a.r>b.r;
    return (kuai[a.l]^kuai[a.r])&1?a.x<b.x:a.x>b.x;
}
inline void add(int now){if (++CNT[now]==1) uk[now]=ku[n-now]=1;}
inline void del(int now){if (--CNT[now]==0) uk[now]=ku[n-now]=0;}
signed main(){
	n=iut(); Q=iut();
	for (rr int i=1;i<317;++i) Sqrt[i*i]=i;
	for (rr int i=1;i<N;++i) if (!Sqrt[i]) Sqrt[i]=Sqrt[i-1];
	for (rr int i=1;i<=n;++i) a[i]=iut(),kuai[i]=(i-1)/Sqrt[(n+Q)>>1]+1;
	for (rr int i=1;i<=Q;++i) q[i]=(five){iut(),iut(),iut(),iut(),i};
	sort(q+1,q+1+Q,cmp);
	for (rr int i=1,L=q[1].l,R=L-1;i<=Q;++i){
		while (L>q[i].l) add(a[--L]);
		while (L<q[i].l) del(a[L++]);
		while (R>q[i].r) del(a[R--]);
		while (R<q[i].r) add(a[++R]);
		switch (q[i].opt){
			case 1:ans[q[i].rk]=(uk&(uk<<q[i].x)).any(); break;
			case 2:ans[q[i].rk]=(uk&(ku>>(n-q[i].x))).any(); break;
			case 3:{
				for (rr int j=1;j<=Sqrt[q[i].x];++j)
				if (q[i].x%j==0&&uk[j]&&uk[q[i].x/j]){
					ans[q[i].rk]=1; break;
				}
				break;
			}
		}
	}
	for (rr int i=1;i<=Q;++i)
	if (ans[i]) printf("hana\n");
	    else printf("bi\n");
	return 0;
}
posted @ 2020-10-15 19:20  lemondinosaur  阅读(72)  评论(0编辑  收藏  举报