BZOJ-2877: [Noi2012]魔幻棋盤(線段樹(shù))

題目:http://www.lydsy.com/JudgeOnline/problem.php?id=2877

嗯花履,這次好好寫一次題解吧,這題傻叉的寫了半天QAQ :

首先榨崩,由歐幾里德算法,我們知道gcd(a,b)=gcd(a,abs(a-b)),所以:

令G(ai)=gcd(a1,a2,...ai...,an)則啼器,G(ai)=gcd(a1,a2-a1,...,an-a(n-1))玛追,所以對(duì)于矩陣[l,r,x,y](表示矩陣四個(gè)頂點(diǎn)中税课,最小的行數(shù)為l闲延,最大為r,最小的列數(shù)為x韩玩,最大的為y)垒玲,設(shè)題目中的定點(diǎn)為(px,py),則答案為:

G(a(i,j))(l<=i<=r,x<=j<=y)

=G( G(a(i,j)(x<=j<=y) ) (l<=i<=r)

=G( gcd( G( a( i , j ) - a( i , j - 1 ) ) , a( i , py ) ) ( x < j <= y ) ) ( l <= i <= r )

=gcd( G( G( a( i , j ) - a( i , j - 1 ) ) ( l <= i <= r ) ) ( x < j <= y ) , G( a( i , py ) ) ( l <= i <= r ) )

那么拆一下:

G( a( i , py ) ) ( l <= i <= r ) = gcd( a( px , py ) , G( a( i , py ) - a( i - 1 , py ) ) ( l < i <= r ) )

G( G( a( i , j ) - a( i , j - 1 ) ) ) ( l <= i <= r ) ( x < j <= y )

= G( gcd( a( px , j ) - a( px , j - 1 ) , G( [ a( i , j ) - a( i , j - 1 ) ] - [ a( i - 1 , j ) - a( i - 1 , j - 1 ) ] ) ( l < i <= r ) ) )( x < j <= y )

= gcd( G( a( px , j ) - a( px , j - 1 ) ) ( x < j <= y ) , G( a( i , j ) - a( i , j - 1 ) - a( i - 1 , j ) + a( i - 1 , j - 1 ) )( l < i <= r && x < j <= y ) )

然后,用兩棵一維線段樹(shù)維護(hù)G( a( i , py ) - a( i - 1 , py ) ) ( l < i <= r ) , G( a( px , j ) - a( px , j - 1 ) ) ( x < j <= y ) ,用一棵二維線段樹(shù)維護(hù)G( a( i , j ) - a( i , j - 1 ) - a( i - 1 , j ) + a( i - 1 , j - 1 ) )( l < i <= r && x < j <= y ) 找颓,我們神奇的發(fā)現(xiàn)每次修改操作在這三棵線段樹(shù)上都是單點(diǎn)修改合愈,然后就可以AC了。

時(shí)間復(fù)雜度:O(n log^3 n)

代碼:

#include <cstdio>

#include <algorithm>

#include <cstring>

 

using namespace std ;

 

#define REP( i , l , r ) for ( int i = l ; i <= r ; ++ i )

#define rep( i , x ) for ( int i = 0 ; i ++ < x ; )

#define Rep( i , x ) for ( int i = 0 ; i < x ; ++ i )

 

const int maxn = 501000 ;

 

typedef long long ll ;

 

ll gcd( ll x , ll y ) {

    if ( x < y ) swap( x , y ) ;

    for ( ll t ; y ; t = y , y = x % y , x = t ) ;

    return x ;

}

 

struct node {

     

    int l , r , mid ;

    ll g ;

    node *lc , *rc ;

     

    inline void update(  ) {

        g = gcd( abs( lc -> g ) , abs( rc -> g ) ) ;

    }

     

} sgt[ maxn * 25 ] ;

 

node *pt = sgt ;

 

void build( int l , int r , ll a[] , node* &t ) {

    t = pt ++ ;

    t -> l = l , t -> r = r ;

    if ( l == r ) {

        t -> g = a[ l ] ; return ;

    }

    t -> mid = ( l + r ) >> 1 ;

    build( l , t -> mid , a , t -> lc ) , build( t -> mid + 1 , r , a , t -> rc ) ;

    t -> update(  ) ;

}

 

void change( int p , ll d , node *t ) {

    if ( t -> l == t -> r ) {

        t -> g += d ; return ;

    }

    change( p , d , p <= t -> mid ? t -> lc : t -> rc ) ;

    t -> update(  ) ;

}

 

ll query( int l , int r , node *t ) {

    if ( l > r ) return 0 ;

    if ( l == t -> l && r == t -> r ) return abs( t -> g ) ;

    if ( r <= t -> mid ) return query( l , r , t -> lc ) ;

    if ( l > t -> mid ) return query( l , r , t -> rc ) ;

    return gcd( query( l , t -> mid , t -> lc ) , query( t -> mid + 1 , r , t -> rc ) ) ;

}

 

struct Node {

     

    int l , r , mid ;

    node *t ;

    Node *lc , *rc ;

     

    inline void Update( int p ) {

        node *l = lc -> t , *r = rc -> t , *m = t ;

        for ( ; ; ) {

            m -> g = gcd( abs( l -> g ) , abs( r -> g ) ) ;

            if ( m -> l == m -> r ) break ;

            if ( p <= m -> mid ) {

                l = l -> lc , r = r -> lc , m = m -> lc ;

            } else {

                l = l -> rc , r = r -> rc , m = m -> rc ;

            }

        }

    }

     

} Sgt[ maxn << 2 ] ;

 

Node *Root , *Pt = Sgt ;

 

ll a[ maxn ] , del[ maxn ] , b[ maxn ] ;

int n , m , q , px , py ;

 

#define chose( x , y ) ( ( ( ( x - 1 ) * m + y ) > 0 && ( ( x - 1 ) * m + y ) <= ( n * m ) ) ? ( ( x - 1 ) * m + y ) : 0 )

 

void Merge( node *l , node *r , node* &t ) {

    t = pt ++ ;

    t -> l = l -> l , t -> r = l -> r , t -> mid = l -> mid , t -> g = gcd( l -> g , r -> g ) ;

    if ( t -> l == t -> r ) return ;

    Merge( l -> lc , r -> lc , t -> lc ) , Merge( l -> rc , r -> rc , t -> rc ) ;

}

 

void Build( int l , int r , Node* &t ) {

    t = Pt ++ ;

    t -> l = l , t -> r = r ;

    if ( l == r ) {

        rep( i , m ) b[ i ] = del[ chose( l , i ) ] ;

        build( 1 , m , b , t -> t ) ;

        return ;

    }

    t -> mid = ( l + r ) >> 1 ;

    Build( l , t -> mid , t -> lc ) , Build( t -> mid + 1 , r , t -> rc ) ;

    Merge( t -> lc -> t , t -> rc -> t , t -> t ) ;

}

 

void Change( int x , int y , ll d , Node *t ) {

    if ( t -> l == t -> r ) {

        change( y , d , t -> t ) ; return ;

    }

    Change( x , y , d , x <= t -> mid ? t -> lc : t -> rc ) ;

    t -> Update( y ) ;

}

 

ll Query( int l , int r , int x , int y , Node *t ) {

    if ( l > r ) return 0 ;

    if ( t -> l == l && t -> r == r ) return query( x , y , t -> t ) ;

    if ( r <= t -> mid ) return Query( l , r , x , y , t -> lc ) ;

    if ( l > t -> mid ) return Query( l , r , x , y , t -> rc ) ;

    return gcd( Query( l , t -> mid , x , y , t -> lc ) , Query( t -> mid + 1 , r , x , y , t -> rc ) ) ;

}

 

node *root[ 2 ] ;

ll num ;

 

int cnt = 0 ;

 

inline ll solve( int l , int r , int x , int y ) {

    ll ans = abs( num ) ;

    ans = gcd( ans , Query( l + 1 , r , x + 1 , y , Root ) ) ;

    ans = gcd( ans , query( x + 1 , y , root[ 0 ] ) ) ;

    ans = gcd( ans , query( l + 1 , r , root[ 1 ] ) ) ;

    return ans ;

}

 

inline void modify( int l , int r , int x , int y , ll d ) {

    if ( r + 1 <= n ) {

        if ( y + 1 <= m ) Change( r + 1 , y + 1 , d , Root ) ;

        Change( r + 1 , x , -d , Root ) ;

    }

    if ( y + 1 <= m ) Change( l , y + 1 , -d , Root ) ;

    Change( l , x , d , Root ) ;

    if ( l <= px && r >= px ) {

        change( x , d , root[ 0 ] ) ;

        if ( y + 1 <= m ) change( y + 1 , -d , root[ 0 ] ) ;

        if ( x <= py && y >= py ) num += d ;

    }

    if ( x <= py && y >= py ) {

        change( l , d , root[ 1 ] ) ;

        if ( r + 1 <= n ) change( r + 1 , -d , root[ 1 ] ) ;

    }

}

 

int main(  ) {

    scanf( "%d%d%d%d%d" , &n , &m , &px , &py , &q ) ;

    memset( del , 0 , sizeof( del ) ) , memset( a , 0 , sizeof( a ) ) ;

    rep( i , n ) rep( j , m ) scanf( "%lld" , &a[ chose( i , j ) ] ) ;

    rep( i , n ) rep( j , m ) {

        del[ chose( i , j ) ] = a[ chose( i , j ) ] - a[ chose( i - 1 , j ) ] - a[ chose( i , j - 1 ) ] + a[ chose( i - 1 , j - 1 ) ] ;

    }

    Build( 1 , n , Root ) ;

    rep( i , m ) b[ i ] = a[ chose( px , i ) ] - a[ chose( px , i - 1 ) ] ;

    build( 1 , m , b , root[ 0 ] ) ;

    rep( i , n ) b[ i ] = a[ chose( i , py ) ] - a[ chose( i - 1 , py ) ] ;

    build( 1 , n , b , root[ 1 ] ) ;

    int x , y , z , l , r ; ll d ;

    num = a[ chose( px , py ) ] ;

    while ( q -- ) {

        scanf( "%d" , &z ) ;

        if ( ! z ) {

            scanf( "%d%d%d%d" , &l , &x , &r , &y ) ;

            printf( "%lld\n" , solve( px - l , px + r , py - x , py + y ) ) ;

        } else {

            scanf( "%d%d%d%d%lld" , &l , &x , &r , &y , &d ) ;

            modify( l , r , x , y , d ) ;

        }

    }

    return 0 ;

}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末击狮,一起剝皮案震驚了整個(gè)濱河市佛析,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌彪蓬,老刑警劉巖寸莫,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異寞焙,居然都是意外死亡储狭,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門捣郊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)辽狈,“玉大人,你說(shuō)我怎么就攤上這事呛牲」蚊龋” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵娘扩,是天一觀的道長(zhǎng)着茸。 經(jīng)常有香客問(wèn)我,道長(zhǎng)琐旁,這世上最難降的妖魔是什么涮阔? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮灰殴,結(jié)果婚禮上敬特,老公的妹妹穿的比我還像新娘。我一直安慰自己牺陶,他們只是感情好伟阔,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著掰伸,像睡著了一般皱炉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上狮鸭,一...
    開(kāi)封第一講書(shū)人閱讀 51,692評(píng)論 1 305
  • 那天合搅,我揣著相機(jī)與錄音多搀,去河邊找鬼。 笑死灾部,一個(gè)胖子當(dāng)著我的面吹牛酗昼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播梳猪,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼麻削,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了春弥?” 一聲冷哼從身側(cè)響起呛哟,我...
    開(kāi)封第一講書(shū)人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎匿沛,沒(méi)想到半個(gè)月后扫责,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡逃呼,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年鳖孤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片抡笼。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡苏揣,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出推姻,到底是詐尸還是另有隱情平匈,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布藏古,位于F島的核電站增炭,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏拧晕。R本人自食惡果不足惜隙姿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望厂捞。 院中可真熱鬧输玷,春花似錦、人聲如沸蔫敲。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)奈嘿。三九已至,卻和暖如春吞加,著一層夾襖步出監(jiān)牢的瞬間裙犹,已是汗流浹背尽狠。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留叶圃,地道東北人袄膏。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像掺冠,于是被迫代替她去往敵國(guó)和親沉馆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 拿到這一年的六千塊錢的獎(jiǎng)勵(lì)性績(jī)效真的有種絕望的感覺(jué)德崭。三十五歲已經(jīng)是人生最尷尬的時(shí)候斥黑。別人說(shuō)你老了,可你覺(jué)得自己不過(guò)...
    幸福一生_61a7閱讀 207評(píng)論 0 0
  • 月落了輕紗 掩蓋了誰(shuí)的哀傷 夢(mèng)留住了畫(huà) 遮住誰(shuí)的木蘭香 樹(shù)梢勾勒的黑影 沉淀了誰(shuí)的思緒 泛黃是那油蠟燈 滾燙而不知...
    玉米粉閱讀 211評(píng)論 0 4
  • 張艷 焦點(diǎn)網(wǎng)絡(luò)初級(jí)7期 堅(jiān)持分享第35天 今天改了一下學(xué)生的周末作業(yè),除了幾個(gè)認(rèn)真寫的憾股,都是隨便編的答案鹿蜀,應(yīng)付,氣...
    柚橙媽咪閱讀 226評(píng)論 0 0