P5355 [Ynoi2017] 由乃的玉米田

题目

P5355 [Ynoi2017] 由乃的玉米田

P3674 小清新人渣的本愿的加强版,多了除操作。

分析

莫队+(bitset)+根号分治

对于前三个操作,请看这里

这里只讨论除该怎么解决。

首先我们莫队无法很好地维护,于是考虑另外的思路。

我们可以考虑直接枚举一个数作为商,然后查看是否有被除数,但是这样做会因为 (x) 很小的时候复杂度很高。

于是考虑根号分治,对于 (sqrt{n}leq x) 的询问除,直接莫队,在询问的时候 (O(sqrt{n})) 回答即可。

对于 (xleq sqrt{n}) 的询问除,我们考虑单独维护:

因为这样的 (x) 不超过 (sqrt{n}) ,于是可以考虑枚举每一个 (x)

然后我们记 (las[i]) 表示值为 (i) 的最后出现的位置,(res[i]) 表示位置 (i) 在之前的最右端的可匹配到一对 ((a,a*x)) 的左端点位置,两者的更新显然。

那么我们把询问离线到每一个对应的 (x) 处,处理完当前的 (res) 数组后,我们直接可以 (O(1)) 回答每一个询问。(直接查询右端点的 (res[r]) 是否大于等于 (l) 即可)

时间复杂度 (O(nsqrt{n}+frac{nm}{w}))

代码

#include<bits/stdc++.h>
using namespace std;
//#define getchar()(p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
//char buf[1<<21],*p1=buf,*p2=buf;
template <typename T>
inline void read(T &x){
	x=0;char ch=getchar();bool f=false;
	while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	x=f?-x:x;
	return ;
}
template <typename T>
inline void write(T x){
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);
	putchar(x%10^48);
	return ;
}
const int N=1e5+5,V=1e5;
#define ll long long
int n,m,k;
int bl[N];
int a[N],cnt[N],Ans[N],stk[N],top,pos[N],Cnt1,Cnt2;
struct Query{int op,l,r,v,id;}Q[N],Q1[N];
int Now,Num;
bitset<N<<1> Now1,Now2,tmp;
inline void Add(int x){
	cnt[x]++;
	Now1.set(x+V),Now2.set(V-x);
	return ;
}
inline void Del(int x){
	cnt[x]--;
	if(!cnt[x]) Now1.reset(x+V),Now2.reset(V-x);
	return ;
}
inline bool Cmp(Query x,Query y){return bl[x.l]^bl[y.l]?bl[x.l]<bl[y.l]:bl[x.l]&1?x.r<y.r:x.r>y.r;}
vector<int> v[N];
inline bool Ask(int x){
	for(int i=0;i<v[x].size();i++){
		int y=v[x][i];
		if(cnt[y]&&cnt[x/y]) return true;
	}
	return false;
} 
inline bool Ask1(int x){
	for(int i=1;i<=V/x;i++) if(cnt[i]&&cnt[i*x]) return true;
	return false;
}
int las[N],res[N];
vector<Query> vec[N];
int main(){
	for(int i=1;i<=V;i++) for(int j=i;j<=V;j+=i) v[j].push_back(i);
	read(n);read(m);
	for(int i=1;i<=n;i++) read(a[i]);
	const int t=sqrt(n),lim=sqrt(V);
	for(int i=1;i<=m;i++){
		int op,l,r,x;
		read(op),read(l),read(r),read(x);
		if(op==4&&x<=lim) vec[x].push_back(Query{4,l,r,x,i});
		else Q[++Cnt1]=Query{op,l,r,x,i};
	}
	for(int x=1;x<=lim;x++){
		if(vec[x].empty()) continue;
		for(int i=0;i<=V;i++) las[i]=res[i]=0;
		int l=0;
		for(int i=1;i<=n;i++){
			las[a[i]]=i;
			if(a[i]*x<=V) l=max(l,las[a[i]*x]);
			if(a[i]%x==0) l=max(l,las[a[i]/x]);
			res[i]=l;
		}
		int len=vec[x].size();
		for(int i=0;i<len;i++){
			Query t=vec[x][i];
			Ans[t.id]=(res[t.r]>=t.l);
		}
	}
	for(int i=1;i<=n;i++) bl[i]=(i-1)/t+1;
	sort(Q+1,Q+Cnt1+1,Cmp);
	int l=1,r=0;
	for(int i=1;i<=Cnt1;i++){
		while(l>Q[i].l) Add(a[--l]);
		while(r<Q[i].r) Add(a[++r]);
		while(l<Q[i].l) Del(a[l++]);
		while(r>Q[i].r) Del(a[r--]);
		if(Q[i].op==1) tmp=(Now1>>Q[i].v)&Now1,Ans[Q[i].id]=tmp.any();
		else if(Q[i].op==2) tmp=(Now1>>Q[i].v)&Now2,Ans[Q[i].id]=tmp.any();
		else if(Q[i].op==3) Ans[Q[i].id]=Ask(Q[i].v);
		else Ans[Q[i].id]=Ask1(Q[i].v);
	}
	for(int i=1;i<=m;i++) puts(Ans[i]?"yuno":"yumi");
	return 0;
} 
原文地址:https://www.cnblogs.com/Akmaey/p/14707964.html