[bzoj4722]由乃

题目描述

由于一周目的由乃穿越到了三周目,并带来了巨大的影响,改变了三周目所有未来日记所有者的命运所以三周目的
神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);
    }
}
发布了836 篇原创文章 · 获赞 314 · 访问量 59万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览