P5355 [Ynoi2017] 由乃的玉米田 莫队 根号分治 数据结构

题意:

戳这里

分析:

弱化版 : 小清新人渣的本愿

分操作考虑:

  1. 加 or 减

    本质就是查询区间内是否有一个数对,想了半天都没有想到有什么数据结构可以做,最后发现,竟然还有个 (bitset)

    维护一个正着的 (bitset) 和一个反着的 (bitset) 就可以同时实现加减的操作

  2. 最水的一个操作,(O(sqrt x))枚举因数 ,(bitset) 判断是否存在

  3. 可以转化成乘法,判断 (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;
}