【HDU】5314 Happy King【动态树(点分治)】

来源:互联网 发布:淘宝运营报价 编辑:程序博客网 时间:2024/05/17 21:53

传送门:【HDU】5314 Happy King

算法分析:
点分治,子树去重类可做。对于一个重心,取出所有路径按照最大值排序,扫下最小值,插入到线段树里维护个数,双指针扫扫解决。然后对所有重心的儿子对应的子树再做一次去重。这个方法我是今早在床上想了下想到的。
我是动态树,动态树比较裸,对点权排序,然后双指针扫扫,接下来就是链接两棵子树或者拆分两棵子树时的子树的siz。子树siz可以用两个变量维护,一个维护splay树内的子树的siz和,一个维护从这个点连出去的不在splay树上的子树的siz和。然后就做完了。

点分治一般做法复杂度O(Nlog2N),听说神奇的单调队列做法可以达到O(NlogN),动态树复杂度O(NlogN)

PS:比赛的时候,没从子树去重类入手,用枚举子树的方法思考怎么都不能去除重复的计数,于是没想到点分治的方法怎么做。而我想到用动态树的瞬间就知道怎么用动态树做了,但是敲到一半的时候竟然傻逼的找了个奇怪的理由否决了= =也是傻逼……导致比赛的时候没做出来……

my  code:

#include <stdio.h>#include <string.h>#include <bitset>#include <algorithm>using namespace std ;typedef long long LL ;#define clr( a , x ) memset ( a , x , sizeof a )const int MAXN = 100005 ;const int MAXM = 10000005 ;const int MAXE = 200005 ;const int INF = 0x3f3f3f3f ;struct Edge {    int v , n ;    Edge () {}    Edge ( int v , int n ) : v ( v ) , n ( n ) {}} ;struct Point {    int x , idx ;    bool operator < ( const Point& a ) const {        return x < a.x ;    }} ;LL ans ;struct Node* null ;struct Node {    Node* c[2] ;           Node* f ;    int siz , outsiz ;    int flip ;    void newnode () {        c[0] = c[1] = f = null ;        flip = 0 ;        siz = 1 ;        outsiz = 0 ;    }    void reverse () {        if ( this == null ) return ;        swap ( c[0] , c[1] ) ;        flip ^= 1 ;    }    void up () {        if ( this == null ) return ;        siz = c[0]->siz + c[1]->siz + c[0]->outsiz + c[1]->outsiz + 1 ;    }    void down () {        if ( this == null ) return ;        if ( flip ) {            c[0]->reverse () ;            c[1]->reverse () ;            flip = 0 ;        }    }    bool is_root () {        return f == null || f->c[0] != this && f->c[1] != this ;    }    void setc ( Node* o , int d ) {        c[d] = o ;        o->f = this ;    }    void sign_down () {        if ( !is_root () ) f->sign_down () ;        down () ;    }    void rot ( int d ) {        Node* p = f ;        Node* g = p->f ;        p->setc ( c[d] , !d ) ;        if ( !p->is_root () ) g->setc ( this , f == g->c[1] ) ;        else f = g ;        setc ( p , d ) ;        p->up () ;    }    Node* splay () {        sign_down () ;        while ( !is_root () ) {            if ( f->is_root () ) rot ( this == f->c[0] ) ;            else {                if ( f == f->f->c[0] ) {                    if ( this == f->c[0] ) f->rot ( 1 ) , rot ( 1 ) ;                    else rot ( 0 ) , rot ( 1 ) ;                } else {                    if ( this == f->c[1] ) f->rot ( 0 ) , rot ( 0 ) ;                    else rot ( 1 ) , rot ( 0 ) ;                }            }        }        up () ;        return this ;    }    Node* access () {        Node* o = this ;        Node* x = null ;        while ( o != null ) {            if ( x != null ) {                while ( x->c[0] != null ) x = x->c[0] ;                x->splay () ;            }            o->splay () ;            o->outsiz += o->c[1]->outsiz + o->c[1]->siz ;            o->outsiz -= x->outsiz + x->siz ;            o->setc ( x , 1 ) ;            o->up () ;            x = o ;            o = o->f ;        }        return splay () ;    }    void make_root () {        access ()->reverse () ;        splay () ;    }    void link ( Node* o ) {        make_root () ;        o->make_root () ;        ans += ( LL ) ( siz + outsiz ) * ( o->siz + o->outsiz ) ;        o->outsiz += siz + outsiz ;        f = o ;    }    void cut () {        access () ;        c[0]->f = null ;        c[0] = null ;        up () ;    }    void cut ( Node* o ) {        make_root () ;        o->cut () ;    }} ;Node pool[MAXN] ;Node* cur ;Node* node[MAXN] ;Edge E[MAXE] ;int H[MAXN] , cntE ;Point p[MAXN] ;int is[MAXN] ;int n , D ;void clear () {    cur = pool ;    cur->newnode () ;    null = cur ++ ;    null->siz = 0 ;}void init () {    cntE = 0 ;    clr ( is , 0 ) ;    clr ( H , -1 ) ;}void addedge ( int u , int v ) {    E[cntE] = Edge ( v , H[u] ) ;    H[u] = cntE ++ ;}void scanf ( int& x , char c = 0 ) {    while ( ( c = getchar () ) < '0' ) ;    x = c - '0' ;    while ( ( c = getchar () ) >= '0' ) x = x * 10 + c - '0' ;}void solve () {    int u , v ;    init () ;    clear () ;    scanf ( n ) ;    scanf ( D ) ;    for ( int i = 1 ; i <= n ; ++ i ) {        scanf ( p[i].x ) ;        p[i].idx = i ;        cur->newnode () ;        node[i] = cur ++ ;    }    sort ( p + 1 , p + n + 1 ) ;    for ( int i = 1 ; i < n ; ++ i ) {        scanf ( u ) ;        scanf ( v ) ;        addedge ( u , v ) ;        addedge ( v , u ) ;    }    int l = 1 ;    ans = 0 ;    for ( int i = 1 ; i <= n ; ++ i ) {        while ( l <= i && p[i].x - p[l].x > D ) {            int u = p[l].idx ;            for ( int j = H[u] ; ~j ; j = E[j].n ) {                int v = E[j].v ;                if ( !is[v] ) continue ;                node[u]->cut ( node[v] ) ;            }            is[u] = 0 ;            ++ l ;        }        int u = p[i].idx ;        for ( int j = H[u] ; ~j ; j = E[j].n ) {            int v = E[j].v ;            if ( !is[v] ) continue ;            node[u]->link ( node[v] ) ;        }        is[u] = 1 ;    }    printf ( "%lld\n" , ans * 2 ) ;}int main () {    int T ;    scanf ( T ) ;    for ( int i = 1 ; i <= T ; ++ i ) {        solve () ;    }    return 0 ;}
0 0