Luogu P5355 [Ynoi2017]由乃的玉米田

Posted cjoiershiina-mashiro

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu P5355 [Ynoi2017]由乃的玉米田相关的知识,希望对你有一定的参考价值。

Link
开一个桶记录每个数字出现过多少次,同时用bitset维护(x)是否出现过。
那么查询是否有两个数的差为(x)就是把bitset右移(x)位然后与自己,如果有位置为(1)那么就说明存在。
查询是否有两个数的和为(x)也可以类似地做,多开一个bitset维护(10^5-x)是否出现过。
查询是否有两个数的积为(x)可以直接枚举因数查询,注意特判(x=0)的情况。
最后是查询是否有两个数的商为(x),首先特判(x=0)的情况,对于(xge64)的数据,我们可以暴力枚举判断。
对于(1le x<64)的,我们把所有(x)相同询问的放一起并按左端点降序排序,用树状数组维护一下以每个点为左端点的最左右端点就好了。
时间复杂度是(O(frac{n^2}{64}+nsqrt n+64nlog n))
(实际上除法那里最优的分治边界应该是(sqrt{frac n{log n}}),这样复杂度就是(O(frac{n^2}{64}+nsqrt{nlog n})),不过(64)也差不多)

#pragma GCC optimize(3)
#include<cmath>
#include<cstdio>
#include<cctype>
#include<bitset>
#include<cstring>
#include<algorithm>
namespace IO
{
    char ibuf[(1<<21)+1],*iS,*iT;
    char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
    int read(){int x=0,c=Get();while(!isdigit(c))c=Get();while(isdigit(c))x=x*10+c-48,c=Get();return x;}
}using IO::read;
using std::sort;
using std::bitset;
int min(int a,int b){return a<b? a:b;}
const int N=100007,U=100000,inf=0x3f3f3f3f;
bitset<N>S,T;
int n,m,bel[N],t[N],pos[N],a[N],ans[N];
struct node{int o,l,r,x,id;}q[N],p[N];
int operator<(const node&a,const node&b){return bel[a.l]==bel[b.l]? a.r<b.r:a.l<b.l;}
void add(int x){if(++t[x]==1)S[x]=T[U-x]=1;}
void del(int x){if(!--t[x])S[x]=T[U-x]=0;}
int askmul(int x){if(!x)return S[0];for(int i=1;i*i<=x;++i)if(!(x%i)&&S[i]&&S[x/i])return 1;return 0;}
int askdiv(int x){if(!x)return S[0]&&S.count()>1;for(int i=1,j=x;j<=U;++i,j+=x)if(S[i]&&S[j])return 1;return 0;}
void update(int p,int v){for(;p<=n;p+=p&-p)t[p]=min(t[p],v);}
int query(int p){int r=inf;for(;p;p^=p&-p)r=min(r,t[p]);return r;}
int main()
{
    n=read(),m=read();int c=0,B=sqrt(n)+rand()%5;
    for(int i=1;i<=n;++i) a[i]=read(),bel[i]=(i-1)/B+1;
    for(int i=1;i<=m;++i) q[i]={read(),read(),read(),read(),i};
    sort(q+1,q+m+1);
    for(int i=1,L=1,R=0;i<=m;++i)
    {
    int l=q[i].l,r=q[i].r,x=q[i].x;
    if(q[i].o==4&&q[i].x<64&&q[i].x) {p[++c]=q[i];continue;}
    while(l<L) add(a[--L]);
    while(R<r) add(a[++R]);
    while(L<l) del(a[L++]);
    while(r<R) del(a[R--]);
    if(q[i].o==1) ans[q[i].id]=(S&S<<x).any();
    else if(q[i].o==2) ans[q[i].id]=(S&T>>(U-x)).any();
    else if(q[i].o==3) ans[q[i].id]=askmul(x);
    else ans[q[i].id]=askdiv(x);
    }
    sort(p+1,p+c+1,[](const node&a,const node&b){return a.x<b.x||(a.x==b.x&&a.l>b.l);});
    for(int l=1,r;l<=c;l=r+1)
    {
    for(r=l;p[r+1].x==p[l].x&&r<c;++r);
    memset(t,0x3f,sizeof t),memset(pos,0x3f,sizeof pos);
    for(int i=l,j=n;i<=r;++i)
        {
            for(;j>=p[i].l;--j)
            {
        pos[a[j]]=j;
        if(1ll*a[j]*p[l].x<=U) update(j,pos[a[j]*p[l].x]);
        if(!(a[j]%p[l].x)) update(j,pos[a[j]/p[l].x]);
            }
        ans[p[i].id]=p[i].l>p[i].r? 0:query(p[i].r)<=p[i].r;
        }
    }
    for(int i=1;i<=m;++i) puts(ans[i]? "yuno":"yumi");
}

以上是关于Luogu P5355 [Ynoi2017]由乃的玉米田的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ4811[Ynoi2017]由乃的OJ 树链剖分+线段树

bzoj 4811: [Ynoi2017]由乃的OJ

[BZOJ]4810: [Ynoi2017]由乃的玉米田

BZOJ4811 [Ynoi2017]由乃的OJ

莫队bzoj4866: [Ynoi2017]由乃的商场之旅

BZOJ4810 [Ynoi2017]由乃的玉米田