[bzoj4722]由乃 线段树 搜索 st表

来源:互联网 发布:正规淘宝兼职 编辑:程序博客网 时间:2024/05/18 19:44

4722: 由乃

Time Limit: 20 Sec  Memory Limit: 512 MB
[Submit][Status][Discuss]

Description

由于一周目的由乃穿越到了三周目,并带来了巨大的影响,改变了三周目所有未来日记所有者的命运所以三周目的
神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)所以她请您——未来的国家队队员来帮助她啦

Input

第一行三个数n , m , v,意义如题所述
之后一行n个数,表示序列a
之后m行每行三个数opt , l , r,表示操作类型是1还是2,操作的区间是[l , r]

Output

m行,每行一个字符串 Yuno 或者 Yuki 表示能否选出这两个集合

Sample Input

20 20 152
3 26 133 54 79 81 72 109 66 91 82 100 35 23 104 17 51 114 12 58
2 1 17
2 6 12
1 1 12
2 3 5
2 11 11
2 7 19
2 6 15
1 5 12
1 1 9
1 10 19
2 3 19
2 6 20
2 1 13
2 1 15
2 1 9
1 1 1
2 1 7
2 7 19
2 6 19
2 3 6

Sample Output

Yuno
Yuno
Yuno
Yuno
Yuki

HINT

总算在bzoj上出题了呀
这下可以安心退役了~
总共有10组数据
对于100%的数据,n , m <= 100000 , v <= 1000,数据没有梯度

Source

结果lxl noip考了595,%%%

许愿noip不爆炸

这道题我并不知道怎么证明大于13一定有解

小于14时一半一半搜索一下

立方用线段树维护

开始想快速幂,但是区间乘没有模数怎么搞?所以st表吧

#include <bits/stdc++.h>using namespace std;const int N = 100000 + 5;int flag[N<<2], n, m, mod, a[N], st[1005][25];void change( int &x, int y ){int j = 20;while( j >= 0 ){if( y >= (1<<j) ){x = st[x][j];y -= (1<<j);}j --;}}void pushdown( int k ){if( flag[k] ){flag[k<<1] += flag[k];flag[k<<1|1] += flag[k];flag[k] = 0;}}void change( int k, int l, int r, int L, int R ){if( L <= l && r <= R ){flag[k] ++; return ;}int mid = l + r >> 1;pushdown( k );if( L <= mid ) change( k<<1, l, mid, L, R );if( R >  mid ) change( k<<1|1, mid + 1, r, L, R );}void query( int k, int l, int r, int x ){if( l == r ){change( a[l], flag[k] ); flag[k] = 0;return ;}pushdown( k );int mid = l + r >> 1;if( x <= mid ) query( k<<1, l, mid, x );else query( k<<1|1, mid + 1, r, x );}int q[N], tail, mi; bool hav[10005], lxl;int opt, lf, rg;void dfs1( int pos, int sum, bool f ){if( pos > mi ){if( f && sum == 0 ) lxl = 1;if( f && sum >= 0 && !hav[sum] ) hav[q[++tail]=sum] = 1;return ;}dfs1( pos + 1, sum, f ); if( lxl ) return ;dfs1( pos + 1, sum + a[pos] + 1, 1 ); if( lxl ) return ;dfs1( pos + 1, sum - a[pos] - 1, 1 );}void dfs2( int pos, int sum, bool f ){if( pos > rg ){if( f && sum == 0 ) lxl = 1;if( f && sum >= 0 && hav[sum] ) lxl = 1;return ;}dfs2( pos + 1, sum, f ); if( lxl ) return ;dfs2( pos + 1, sum + a[pos] + 1, 1 ); if( lxl ) return ;dfs2( pos + 1, sum - a[pos] - 1, 1 );}int main(){scanf( "%d%d%d", &n, &m, &mod );for( int i = 1; i < mod; i++ ) st[i][0] = i * i % mod * i % mod;for( int j = 1; j <= floor(log(m)/log(2)); j++ )for( int i = 1; i < mod; i++ )st[i][j] = st[st[i][j-1]][j-1];for( int i = 1; i <= n; i ++ ) scanf( "%d", &a[i] );while( m -- ){scanf( "%d%d%d", &opt, &lf, &rg );if( opt == 2 ){change( 1, 1, n, lf, rg ); continue;}if( rg - lf > 11 ){puts("Yuno"); continue;}for( int i = lf; i <= rg; i++ ) query( 1, 1, n, i );mi = lf + rg >> 1; tail = 0; lxl = 0;dfs1( lf, 0, 0 ); dfs2( mi + 1, 0, 0 );for( int i = 1; i <= tail; i ++ ) hav[q[i]] = 0;puts( lxl ? "Yuno" : "Yuki" );}return 0;}



原创粉丝点击