ZOJ 3886 Nico Number(篩素數+Love(線)Live(段)樹)
阿新 • • 發佈:2017-08-21
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:即單點改動。
查詢操作:輸出詢問區間和就可以。
時間復雜度:
預處理:
建樹:
查詢與更新:操作次數
羞恥的代碼君:
這次代碼風格。
。
重在理解重在理解。
/*
* @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(段)樹)