[bzoj4722]由乃

来源:互联网 发布:数据挖掘工程师就业 编辑:程序博客网 时间:2024/06/08 09:09

题目描述

由于一周目的由乃穿越到了三周目,并带来了巨大的影响,改变了三周目所有未来日记所有者的命运所以三周目的
神Deus准备不利用未来日记来决定把神的位置交给谁Deus特别崇拜某知名社会主义国家领导人,因为他的寿命比神
还长,所以他想钦定下一个卡密,而不通过选举他决定钦定三周目的由乃成为卡密,去和一周目的雪辉重逢(终于
做了一件好事了)但是,既然是钦定,那么肯定还是要做做样子的,以防某些来自香港的记者造个大新闻,导致被
批判一番所以Deus决定,出一道OI题来考察由乃有没有当神的能力如果你没有看过这个番,以上内容可以无视
给一个长为n的序列a,每个数在0到v - 1之间,有m次操作。
操作1:每次询问一个区间中是否可以选出两个下标的集合X,Y,满足:
1.X和Y没有交集
2.设集合X中有一个元素是i,则其对集合X的贡献是a[i] + 1,要求集合X的元素的总贡献和集合Y的元素的总贡献
相等如果可以选出这两个集合,输出 Yuno否则输出 Yuki
操作2:修改一个区间l,r之间的数,使得所有l <= i <= r,a[i] = a[i] * a[i] * a[i] % v ,即区间立方
如果你没有看过这个番,或者你已经是国家队队员,以下内容可以无视
可以去和雪辉重逢,由乃肯定非常高兴然而可爱的由乃虽然很机智但是并不会OI呀,特别不会数据结构这种神奇的
东西(会数据结构和成为卡密有什么关系吗233333)所以她请您——未来的国家队队员来帮助她啦

玄学

网上有个结论,1000以内的自然数,如果有那么个至少13个,无论是多少总能通过选择其中一些加减得到0。
感谢帮助……13是这样算的
假设区间中选两个集合和相等则一定可以
集合的方案数是2^len,但是值域是len * 1000
解得13
有了这个结论,区间长度太大的可以直接输出了。
不能直接输出的时候区间长度比较小,可以通过折半搜索搜出来。
至于那个区间修改,我们用线段树维护。
但是次幂tag可能会爆。准确来说模数鬼畜不可能得到次数。
因此考虑倍增f[i,j]=i32j
那么有f[i,j]=f[f[i,j1],j1]
然后得到新值时将tag二进制拆分然后利用倍增数组即可。
我们的懒标记应该特别懒除非询问叶子不然也不清掉,这样会快些。

#include<cstdio> #include<algorithm>#include<cmath>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;const int maxn=100000+10;int tag[maxn*4],b[maxn],a[maxn],lf[1000+10][20+5];bool bz[10000],leaf[maxn*4];int i,j,k,l,r,mid,t,n,m,mo,top;bool czy;int read(){    int x=0,f=1;    char ch=getchar();    while (ch<'0'||ch>'9'){        if (ch=='-') f=-1;        ch=getchar();    }    while (ch>='0'&&ch<='9'){        x=x*10+ch-'0';        ch=getchar();    }    return x*f;}void mark(int p,int v){    tag[p]+=v;}void down(int p){    if (tag[p]){        mark(p*2,tag[p]);        mark(p*2+1,tag[p]);        tag[p]=0;    }}void change(int p,int l,int r,int a,int b){    if (l==a&&r==b){        mark(p,1);        return;    }    down(p);    int mid=(l+r)/2;    if (b<=mid) change(p*2,l,mid,a,b);    else if (a>mid) change(p*2+1,mid+1,r,a,b);    else change(p*2,l,mid,a,mid),change(p*2+1,mid+1,r,mid+1,b);}int count(int x,int y){    int j=20;    while (j>=0){        if (y>=(1<<j)){            x=lf[x][j];            y-=(1<<j);        }        j--;    }    return x;}void query(int p,int l,int r,int w){    if (l==r){        a[l]=count(a[l],tag[p]);        tag[p]=0;        return;    }    down(p);    int mid=(l+r)/2;    if (w<=mid) query(p*2,l,mid,w);else query(p*2+1,mid+1,r,w);}void getleaf(int p,int l,int r){    if (l==r){        leaf[p]=1;        return;    }    int mid=(l+r)/2;    getleaf(p*2,l,mid);getleaf(p*2+1,mid+1,r);}void dfs1(int x,int y,bool f){    if (x==mid+1){        if (f&&y==0) czy=1;        if (f&&y>=0&&!bz[y]){            b[++top]=y;            bz[y]=1;        }        return;    }    dfs1(x+1,y,f);    if (czy) return;    dfs1(x+1,y+a[x]+1,1);    if (czy) return;    dfs1(x+1,y-a[x]-1,1);}void dfs2(int x,int y,bool f){    if (x==r+1){        if (f&&y==0) czy=1;        if (f&&y>=0&&bz[y]) czy=1;        return;    }    dfs2(x+1,y,f);    if (czy) return;    dfs2(x+1,y+a[x]+1,1);    if (czy) return;    dfs2(x+1,y-a[x]-1,1);}int main(){    //freopen("yuki.in","r",stdin);freopen("yuki.out","w",stdout);    n=read();m=read();mo=read();    fo(i,0,mo-1) lf[i][0]=i*i%mo*i%mo;    fo(j,1,floor(log(m)/log(2)))        fo(i,0,mo-1)            lf[i][j]=lf[lf[i][j-1]][j-1];    fo(i,1,n) a[i]=read();    getleaf(1,1,n);    fo(i,1,m){        t=read();l=read();r=read();        if (t==1){            if (r-l+1>13){                printf("Yuno\n");                //printf("1\n");                continue;            }            fo(j,l,r){                query(1,1,n,j);            }            mid=(l+r)/2;            top=0;            czy=0;            dfs1(l,0,0);            dfs2(mid+1,0,0);            fo(j,1,top) bz[b[j]]=0;            if (czy) printf("Yuno\n");else printf("Yuki\n");            //if (czy) printf("1\n");else printf("0\n");        }        else change(1,1,n,l,r);    }}
0 0