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

传送门:【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 ;
}

你可能感兴趣的:(【HDU】5314 Happy King【动态树(点分治)】)