hdu5930 GCD线段树

题目大意:给一个序列,每次换一个位置的值,求每次更新后任意连续的序列的gcd,有几个不同的。序列长度和数字大小<=10W 修改5w次

题解:一开始求出整个每个不同gcd的值可以出现多少次,更新的话对左端所有相同gcd的段求出来,和右端的的段直接暴力更新,由于两端都最多只有logn段,所以复杂度是可以承受的。

#include 
using namespace std ;
#define maxn 51000
#define maxm 1100000
#define pii pair < int , int >
#define ft first
#define sd second
#define clr( a , x ) memset ( a , x , sizeof a )
#define root 1,1 ,n
#define ls rt<<1
#define rs rt<<1|1
#define lson ls,l,m
#define rson rs,m+1,r
int n , q ;
int a[maxn] ;
int vis[maxm] ;
int val[maxn<<2] ;
vector G[2] ;
int ans ;
int gcd(int x,int y)
{
    if(x> 1 ;
    if ( x <= m ) update ( x , v , lson ) ;
    else update ( x , v , rson ) ;
    val[rt] = gcd ( val[ls] , val[rs] ) ;
}

int query ( int L , int R , int rt , int l , int r ) {
    if ( L <= l && r <= R ) return val[rt] ;
    int m = l + r >> 1 ;
    if ( R <= m ) return query ( L , R , lson ) ;
    if ( m <  L ) return query ( L , R , rson ) ;
    return gcd ( query ( L , R , lson ) , query ( L , R , rson ) ) ;
}

pii queryl ( int R , int v , int rt , int l , int r ) {
    if ( r <= R )
    {
        if ( val[rt] % v == 0 ) return pii ( v , l ) ;
        else if ( l == r ) return pii ( gcd ( v , val[rt] ) , l ) ;
    }
    int m = l + r >> 1 ;
    if ( R <= m ) return queryl ( R , v , lson ) ;
    pii tmp = queryl( R , v , rson ) ;
    if ( tmp.ft < v ) return tmp ;
    return queryl ( R , v , lson ) ;
}

pii queryr ( int L , int v , int rt , int l , int r ) {
    if ( L <= l ) {
        if ( val[rt] % v == 0 ) return pii ( v , l ) ;
        else if ( l == r ) return pii ( gcd ( v , val[rt] ) , l ) ;
    }
    int m = l + r >> 1 ;
    if ( m < L ) return queryr ( L , v , rson ) ;
    pii tmp = queryr ( L , v , lson ) ;
    if ( tmp.ft < v ) return tmp ;
    return queryr ( L , v , rson ) ;
}

void getl ( int i )
{
    int nowgcd = a[i] , lastgcd = query ( 1 , i , root ) , x = i ;
    G[0].push_back ( pii ( a[i] , i ) ) ;
    while ( nowgcd != lastgcd )
    {
        pii y = queryl ( x , nowgcd , root ) ;
        G[0].push_back ( y ) ;
        x = y.sd ;
        nowgcd = y.ft ;
    }
    G[0].push_back ( pii ( nowgcd , 0 ) ) ;
}

void getr ( int i )
{
    int nowgcd = a[i] , lastgcd = query ( i , n , root ) , x = i ;
    G[1].push_back ( pii ( a[i] , i ) ) ;
    while ( nowgcd != lastgcd ) {
        pii y = queryr ( x , nowgcd , root ) ;
        G[1].push_back ( y ) ;
        x = y.sd ;
        nowgcd = y.ft ;
    }
    G[1].push_back ( pii ( nowgcd , n + 1 ) ) ;
}

void add ( int x , int y )
{
    if ( vis[x] == 0 ) ++ ans ;
    vis[x] += y ;
    if ( vis[x] == 0 ) -- ans ;
}

void calc ( int i , int f )
{
    G[0].clear () ;
    G[1].clear () ;
    getl ( i ) ;
    getr ( i ) ;
    for ( int i=1;i


你可能感兴趣的:(经典问题,hdu,线段树)