2738: 矩阵乘法(梁 盾)(分块+主席树)

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2738

实在不想吐槽这个标题什么了,本来想找几道矩阵乘法的水题水水的,结果却成了裸数据结构。。。把X分成sqrt(n)个块,然后在没个块上面套棵主席树就可以啦~

空间复杂度:O( n ^ 2 log n )

时间复杂度:O( n ^ 2 log n + q sqrt( n ) log n )

代码:

#include <cstdio>

#include <algorithm>

#include <cstring>

#include <cmath>

 

using namespace std ;

 

#define MAXN 510

#define L( t ) sgt[ t ].left

#define R( t ) sgt[ t ].right

#define S( t ) sgt[ t ].size

#define MAXV 10001000

#define MAXM 30

#define check( ch ) ( ch >= '0' && ch <= '9' )

 

void getint( int &t ) {

    int ch ; for ( ch = getchar(  ) ; ! check( ch ) ; ch = getchar(  ) ) ;

    t = ch - '0' ;

    for ( ch = getchar(  ) ; check( ch ) ; ch = getchar(  ) ) {

        t *= 10 , t += ch - '0' ;

    }

}

 

int out[ 20 ] ;

 

void putint( int t ) {

    if ( ! t ) putchar( '0' ) ; else {

        out[ 0 ] = 0 ;

        for ( ; t ; t /= 10 ) out[ ++ out[ 0 ] ] = t % 10 ;

        while ( out[ 0 ] -- ) putchar( '0' + out[ out[ 0 ] + 1 ] ) ;

    }

    putchar( '\n' ) ;

}

 

struct node {

    int left , right , size ;

    node(  ) {

        left = right = size = 0 ;

    }

} sgt[ MAXV ] ;

 

int V = 0 ;

 

void Add( int l , int r , int k , int u , int &t ) {

    if ( ! t ) t = ++ V ;

    S( t ) = S( u ) + 1 ;

    if ( l == r ) return ;

    int mid = ( l + r ) >> 1 ;

    if ( k <= mid ) {

        R( t ) = R( u ) ; Add( l , mid , k , L( u ) , L( t ) ) ;

    } else {

        L( t ) = L( u ) ; Add( mid + 1 , r , k , R( u ) , R( t ) ) ;

    }

}

 

struct saver {

    int x , y , v ;

    bool operator < ( const saver &a ) const {

        return v < a.v ;

    }

} c[ MAXN * MAXN ] ;

 

int a[ MAXN ][ MAXN ] , n , N = 0 , b[ MAXN * MAXN ] , q , Rank[ MAXN ][ MAXN ] ;

int len ;

int Begin[ MAXM ] , End[ MAXM ] , M , block[ MAXM ][ MAXN ] , pre[ MAXN ][ MAXN ] ;

 

void Init(  ) {

    getint( n ) , getint( q ) ;

    for ( int i = 0 ; i ++ < n ; ) {

        for ( int j = 0 ; j ++ < n ; ) {

            getint( a[ i ][ j ] ) ;

            c[ ++ N ].v = a[ i ][ j ] ;

            c[ N ].x = i , c[ N ].y = j ;

        }

    }

    sort( c + 1 , c + N + 1 ) ;

    N = 0 ;

    for ( int i = 0 ; i ++ < n * n ; ) {

        if ( i == 1 || c[ i ].v != c[ i - 1 ].v ) b[ ++ N ] = c[ i ].v ;

        Rank[ c[ i ].x ][ c[ i ].y ] = N ;

    }

    len = int( sqrt( n ) ) ; M = n / len ;

    for ( int i = 0 ; i ++ < M ; ) {

        Begin[ i ] = ( i - 1 ) * len + 1 , End[ i ] = i * len ;

    }

    if ( M * len < n ) {

        Begin[ M + 1 ] = M * len + 1 , End[ M + 1 ] = n ;

        ++ M ;

    }

    memset( pre , 0 , sizeof( pre ) ) ;

    memset( block , 0 , sizeof( block ) ) ;

    for ( int i = 0 ; i ++ < n ; ) {

        for ( int j = 0 ; j ++ < n ; ) {

            Add( 1 , N , Rank[ i ][ j ] , pre[ i ][ j - 1 ] , pre[ i ][ j ] ) ;

        }

    }

    for ( int i = 0 ; i ++ < M ; ) {

        for ( int j = 0 ; j ++ < n ; ) {

            int temp = block[ i ][ j - 1 ] ;

            for ( int k = Begin[ i ] ; k <= End[ i ] ; ++ k ) {

                int rec = 0 ;

                Add( 1 , N , Rank[ k ][ j ] , temp , rec ) ;

                temp = rec ;

            }

            block[ i ][ j ] = temp ;

        }

    }

}

 

int range[ MAXN * MAXN ][ 2 ] , rn = 0 ;

 

void getrange( int x1 , int x2 , int y1 , int y2 ) {

    int pos1 = ( x1 - 1 ) / len + 1 , pos2 = ( x2 - 1 ) / len + 1 ;

    rn = 0 ;

    if ( pos1 == pos2 ) {

        if ( x1 == Begin[ pos1 ] && x2 == End[ pos1 ] ) {

            range[ ++ rn ][ 0 ] = block[ pos1 ][ y2 ] ;

            range[ rn ][ 1 ] = block[ pos1 ][ y1 - 1 ] ;

        } else {

            for ( int i = x1 ; i <= x2 ; ++ i ) {

                range[ ++ rn ][ 0 ] = pre[ i ][ y2 ] ;

                range[ rn ][ 1 ] = pre[ i ][ y1 - 1 ] ;

            }

        }

    } else {

        for ( int i = x1 ; i <= End[ pos1 ] ; ++ i ) {

            range[ ++ rn ][ 0 ] = pre[ i ][ y2 ] ;

            range[ rn ][ 1 ] = pre[ i ][ y1 - 1 ] ;

        }

        for ( int i = Begin[ pos2 ] ; i <= x2 ; ++ i ) {

            range[ ++ rn ][ 0 ] = pre[ i ][ y2 ] ;

            range[ rn ][ 1 ] = pre[ i ][ y1 - 1 ] ;

        }

        if ( ( ++ pos1 ) <= ( -- pos2 ) ) {

            for ( int i = pos1 ; i <= pos2 ; ++ i ) {

                range[ ++ rn ][ 0 ] = block[ i ][ y2 ] ;

                range[ rn ][ 1 ] = block[ i ][ y1 - 1 ] ;

            }

        }

    }

}

 

int query( int x1 , int x2 , int y1 , int y2 , int k ) {

    getrange( x1 , x2 , y1 , y2 ) ;

    int l = 1 , r = N ;

    while ( l < r ) {

        int mid = ( l + r ) >> 1 , sum = 0 ;

        for ( int i = 0 ; i ++ < rn ; ) {

            sum += S( L( range[ i ][ 0 ] ) ) , sum -= S( L( range[ i ][ 1 ] ) ) ;

        }

        if ( k <= sum ) {

            r = mid ;

            for ( int i = 0 ; i ++ < rn ; ) {

                range[ i ][ 0 ] = L( range[ i ][ 0 ] ) ;

                range[ i ][ 1 ] = L( range[ i ][ 1 ] ) ;

            }

        } else {

            l = mid + 1 , k -= sum ;

            for ( int i = 0 ; i ++ < rn ; ) {

                range[ i ][ 0 ] = R( range[ i ][ 0 ] ) ;

                range[ i ][ 1 ] = R( range[ i ][ 1 ] ) ;

            }

        }

    }

    return b[ l ] ;

}

 

void Solve(  ) {

    while ( q -- ) {

        int x1 , y1 , x2 , y2 , k ;

        getint( x1 ) , getint( y1 ) , getint( x2 ) , getint( y2 ) ;

        getint( k ) ;

        putint( query( x1 , x2 , y1 , y2 , k ) ) ;

    }

}

 

int main(  ) {

    Init(  ) ;

    Solve(  ) ;

    return 0 ;

}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352

推荐阅读更多精彩内容