1. 程式人生 > >ZOJ 3886 Nico Number(篩素數+Love(線)Live(段)樹)

ZOJ 3886 Nico Number(篩素數+Love(線)Live(段)樹)

lang urn process pos || hide 取模 algorithm padding

problemCode=3886">ZOJ 3886

題意:

定義一種NicoNico數x,x有下面特征:
全部不大於x且與x互質的數成等差數列,如x = 5 ,與5互素且不大於5的數1,2,3,4成等差數列。則5是一個NicoNico數。

再定義三種操作:
1.南小鳥詢問[L, R]內有多少個NicoNico數;
2.果皇把[L, R]內的數全部對v取余;
3.果皇將第K個數換成X。

然後給你一個數列,並對這個數列運行若幹操作

思路:

這樣的問題果斷要用LoveLive樹線段樹來做!
首先我們通過打表發現NicoNico數僅僅可能是素數。2的n次冪。6,所以能夠先預處理,對範圍內的全部NicoNico數進行標記。
建樹過程:假設是NicoNico數則節點值為1,不是則為0。

更新操作1:對區間內的數進行取模即是區間改動。這裏能夠優化一下,假設區間最大值小於v,則不須要改動。

更新操作2:即單點改動。

查詢操作:輸出詢問區間和就可以。

時間復雜度:
預處理:O(x)
建樹:O(n)
查詢與更新:操作次數O(m),每次操作O(logn)加起來是O(mlogn)

羞恥的代碼君:

這次代碼風格。

重在理解重在理解。

/*
* @author FreeWifi_novicer
* language : C++/C
*/
#include<cstdio>
#include<iostream>
#include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<string> #include<map> #include<set> #include<vector> #include<queue> using namespace std; #define clr( x , y ) memset(x,y,sizeof(x)) #define cls( x ) memset(x,0,sizeof(x))
#define mp make_pair #define pb push_back #define lson l , mid , root << 1 #define rson mid + 1 , r , root << 1 | 1 typedef long long lint; typedef long long ll; typedef long long LL; const int maxNico = 1e7 + 500 ; const int maxHonoka = 1e5 + 7 ; int Honoka_max[10 * maxHonoka] ; int Honoka_sum[10 * maxHonoka] ; bool Nico_prime[maxNico]; map<int , int> NicoNicoNi; /* にっこにっこにー☆あなたのハートににこにこにー 笑顏屆ける矢澤にこにこー にこにーって覚えてラブにこー */ void init(){ NicoNicoNi[0] = NicoNicoNi[6] = 1; for( int i = 0 ; i <= 31 ; i++ ){ NicoNicoNi[( 1 << i )] = 1; } cls( Nico_prime ); for( int i = 2 ; i * i <= maxNico ; i++ ){ if( !Nico_prime[i] ) for( int j = i * i ; j <= maxNico ; j+=i ) Nico_prime[j] = 1; } for( int i = 2 ; i <= maxNico ; i++ ) if( !Nico_prime[i] ) NicoNicoNi[i] = 1; } void push_Yazawa( int root ){ Honoka_max[root] = max( Honoka_max[ root << 1 ] , Honoka_max[ root << 1 | 1 ] ); Honoka_sum[root] = Honoka_sum[ root << 1 ] + Honoka_sum[ root << 1 | 1 ] ; } void build_Kotori( int l , int r , int root ){ if( l == r ){ scanf( "%d" , &Honoka_max[root] ); if( NicoNicoNi[Honoka_max[root]] ) Honoka_sum[root] = 1; else Honoka_sum[root] = 0; return ; } int mid = ( l + r ) / 2 ; build_Kotori( lson ); build_Kotori( rson ); push_Yazawa( root ); } void Honoka1( int ql , int qr , int x , int l , int r , int root ){ if( qr < l || ql > r ) return ; if( Honoka_max[root] < x) return ; if( l == r ){ Honoka_max[root] %= x ; if( NicoNicoNi[Honoka_max[root]] ) Honoka_sum[root] = 1; else Honoka_sum[root] = 0; return ; } int mid = ( l + r ) / 2 ; Honoka1( ql , qr , x , lson ); Honoka1( ql , qr , x , rson ); push_Yazawa( root ); } void Honoka2( int pos , int x , int l , int r , int root ){ if( l == pos && r == pos ){ Honoka_max[root] = x ; if( NicoNicoNi[x] ) Honoka_sum[root] = 1; else Honoka_sum[root] = 0; return ; } int mid = ( l + r ) / 2 ; if( mid >= pos ) Honoka2( pos , x , lson ); else Honoka2( pos , x , rson ); push_Yazawa( root ); } int Kotori( int ql , int qr , int l , int r , int root ){ if( ql > r || qr < l ) return 0 ; if( ql <= l && qr >= r ) return Honoka_sum[root]; int res = 0 ; int mid = ( l + r ) / 2 ; if( ql <= mid ) res += Kotori( ql , qr , lson ) ; if( qr > mid ) res += Kotori( ql , qr , rson ) ; return res; } int main(){ //freopen("input.txt","r",stdin); init(); int n ; while( cin >> n ){ build_Kotori( 1 , n , 1 ) ; int m ; cin >> m ; for( int i = 1 ; i <= m ; i++ ){ int num ; scanf( "%d" , &num ); if( num == 1 ){ int left , right ; scanf( "%d%d" , &left , &right ) ; printf( "%d\n" , Kotori( left , right , 1 , n , 1 )); } else if( num == 2 ){ int left , right , mod ; scanf( "%d%d%d" , &left , &right , &mod ) ; Honoka1( left , right , mod , 1 , n , 1 ) ; } else if( num == 3 ){ int pos , x ; scanf( "%d%d" , &pos , &x ) ; Honoka2( pos , x , 1 , n , 1 ) ; } } } return 0; }

ZOJ 3886 Nico Number(篩素數+Love(線)Live(段)樹)