题目描述
由于一周目的由乃穿越到了三周目,并带来了巨大的影响,改变了三周目所有未来日记所有者的命运所以三周目的
神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,j−1],j−1]
然后得到新值时将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);
}
}