BZOJ-3451: Tyvj1953 Normal(FFT+点分治)

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

这题目实在是太神了!由于如果某点x出现在y的子树上贡献1的消费,那么说明x是路径(x,y)上最早选到的,那么答案就是sigma(1/dist(u,v)),然后点分治+FFT统计之,O(n log^2 n)

代码:

#include <cstdio>

#include <cstring>

#include <cmath>

#include <cstdlib>

#include <vector>

 

using namespace std ;

 

#define travel( x ) for ( edge *p = head[ x ] ; p ; p = p -> next )

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

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

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

#define com( a , b ) ( com ) { a , b }

 

typedef long long ll ;

 

const int maxn = 101000 ;

const double PI = acos( -1.0 ) ;

 

struct com {

    double a , b ;

    com operator * ( const com &x ) const {

        return com( ( a * x.a - b * x.b ) , ( b * x.a + a * x.b ) ) ;

    }

    com operator + ( const com &x ) const {

        return com( ( a + x.a ) , ( b + x.b ) ) ;

    }

    com operator - ( const com &x ) const {

        return com( ( a - x.a ) , ( b - x.b ) ) ;

    }

} A[ maxn ] ;

 

int tra[ maxn ] ;

 

inline void FFT( com *a , int N , bool flag ) {

    Rep( i , N ) tra[ i ] = 0 ;

    for ( int i = 1 , j = N >> 1 ; i < N ; i <<= 1 , j >>= 1 ) for ( int k = i ; k < ( i << 1 ) ; ++ k ) tra[ k ] = j ;

    for ( int i = 1 ; i < N ; i <<= 1 ) for ( int j = 0 ; j < i ; ++ j ) tra[ j + i ] |= tra[ j ] ;

    Rep( i , N ) A[ i ] = a[ tra[ i ] ] ;

    double pi = flag ? PI : ( - PI ) ;

    com e , w , rec , ret ;

    for ( int i = 1 ; i < N ; i <<= 1 ) {

        e = com( cos( ( 2.0 * pi ) / double( i << 1 ) ) , sin( ( 2.0 * pi ) / double( i << 1 ) ) ) , w = com( 1 , 0 ) ;

        for ( int j = 0 ; j < i ; ++ j , w = w * e ) {

            for ( int k = j ; k < N ; k += ( i << 1 ) ) {

                rec = A[ k ] , ret = w * A[ k + i ] ;

                A[ k ] = rec + ret , A[ k + i ] = rec - ret ;

            }

        }

    }

    if ( ! flag ) Rep( i , N ) A[ i ].a /= double( N ) ;

    Rep( i , N ) a[ i ] = A[ i ] ;

}

 

com a[ maxn ] , b[ maxn ] , c[ maxn ] ;

ll ans[ maxn ] ;

  

struct edge {

    edge *next ;

    int t ;

} E[ maxn << 1 ] ;

 

edge *pt = E , *head[ maxn ] ;

 

inline void add( int s , int t ) {

    pt -> t = t , pt -> next = head[ s ] ; head[ s ] = pt ++ ;

}

 

inline void addedge( int s , int t ) {

    add( s , t ) , add( t , s ) ;

}

 

bool del[ maxn ] ;

int n , size[ maxn ] , root , rt ;

 

void gets( int now , int fa ) {

    size[ now ] = 1 ;

    travel( now ) if ( ! del[ p -> t ] && p -> t != fa ) {

        gets( p -> t , now ) ;

        size[ now ] += size[ p -> t ] ;

    }

}

 

void getrt( int now , int fa ) {

    if ( root ) return ;

    int ret = size[ rt ] / 2 ;

    bool flag = ( size[ rt ] - size[ now ] ) <= ret ;

    travel( now ) if ( p -> t != fa && ! del[ p -> t ] ) {

        if ( size[ p -> t ] > ret ) flag = false ;

        getrt( p -> t , now ) ;

    }

    if ( flag ) root = now ;

}

 

int h[ maxn ] , cnt[ maxn ] , mh , m , H[ maxn ] ;

 

void geth( int now , int fa ) {

    if ( h[ now ] > mh ) mh = h[ now ] ;

    travel( now ) if ( p -> t != fa && ! del[ p -> t ] ) {

        h[ p -> t ] = h[ now ] + 1 ;

        geth( p -> t , now ) ;

    }

}

 

vector < int > sub[ maxn ] , tak[ maxn ] ;

 

void getsub( int now , int fa , int num ) {

    sub[ num ].push_back( now ) , mh = max( mh , h[ now ] ) ;

    travel( now ) if ( p -> t != fa && ! del[ p -> t ] ) getsub( p -> t , now , num ) ;

}

 

void solve( int now ) {

    gets( now , 0 ) ;

    root = 0 , rt = now ; getrt( now , 0 ) ;

    h[ root ] = 0 ; geth( root , 0 ) ;

    REP( i , 0 , mh ) tak[ i ].clear(  ) , cnt[ i ] = 0 ;

    int Mh = mh ;

    cnt[ 0 ] = 1 , ans[ 0 ] ++ ;

    travel( root ) if ( ! del[ p -> t ] ) {

        sub[ p -> t ].clear(  ) ;

        mh = 0 ; getsub( p -> t , root , p -> t ) ;

        tak[ mh ].push_back( p -> t ) ;

        H[ p -> t ] = mh ;

    }

    REP( i , 0 , Mh ) Rep( j , tak[ i ].size(  ) ) {

        int x = tak[ i ][ j ] , m ;

        for ( m = 1 ; m <= H[ x ] ; m <<= 1 ) ; m <<= 1 ;

        Rep( k , m ) a[ k ] = b[ k ] = com( 0 , 0 ) ;

        REP( k , 0 , H[ x ] ) a[ k ].a = double( cnt[ k ] ) ;

        Rep( k , sub[ x ].size(  ) ) b[ h[ sub[ x ][ k ] ] ].a += 1.0 ;

        FFT( a , m , true ) , FFT( b , m , true ) ;

        Rep( k , m ) c[ k ] = a[ k ] * b[ k ] ;

        FFT( c , m , false ) ;

        Rep( k , m ) ans[ k ] += int( c[ k ].a + 0.5 ) * 2 ;

        Rep( k , sub[ x ].size(  ) ) cnt[ h[ sub[ x ][ k ] ] ] ++ ;

    }

    del[ root ] = true ;

    travel( root ) if ( ! del[ p -> t ] ) solve( p -> t ) ;

}

 

int main(  ) {

    memset( head , 0 , sizeof( head ) ) , memset( ans , 0 , sizeof( ans ) ) ;

    scanf( "%d" , &n ) ;

    REP( i , 2 , n ) {

        int s , t ; scanf( "%d%d" , &s , &t ) ; addedge( ++ s , ++ t ) ;

    }

    memset( del , false , sizeof( del ) ) ;

    solve( 1 ) ;

    double Ans = 0 ;

    REP( i , 0 , n ) Ans += double( ans[ i ] ) / double( i + 1 ) ;

    printf( "%.4f\n" , Ans ) ;

    return 0 ;

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

推荐阅读更多精彩内容

  • 单位里要交工作总结了,这是我在“写字”方面,遇到的一种不得不写的情况,熬了一晚上终于交稿了,细细回顾了一下...
    王家强阅读 718评论 0 0
  • 早起看到朋友圈里分享的一条信息,大意是一个女孩向我的朋友求助:女孩正在和一个男孩谈恋爱,男孩的家里是养殖海参的...
    树籽阅读 160评论 0 1
  • 4月2号的夜里,伴随着急匆匆的脚步和沉重的焦虑,我带着妈妈住进了医院,下丘脑梗塞,让她右半边身体开始麻木不听使唤。...
    执_0304阅读 399评论 0 1
  • 哈哈哈哈哈哈哈哈,看了几个电影片段,听对白就仿佛看中文电影,听他们说对白根本没有转换的感觉,都听懂了。。。。。。。...
    先胜而后战阅读 956评论 0 0