spoj QtreeII(link-cut-tree模板)

Query on a tree II


题意:给一棵树,若干个询问,询问1.(a,b),a到b的路径和。2.(a,b,k)a到b的路径上,第k个点是谁。

解题思路:事实上,这题并未涉及到任何信息的修改,用lca完全可以了。lct似乎有那么点脱裤子放屁的感觉。。不过思路还是挺简单的,建好lct,然后询问的时候,先access(a),然后在access(b)的过程中,一旦发现parent(rt)=0,那么好了,这个rt就是a,b的lca了。。。

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <map>
#include <math.h>
#include <queue>
#include <vector>
#include <string>
#include <iostream>
#include <stdlib.h>
#include <time.h>
#define lowbit(x) (x&(-x))
#define ll __int64
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
#define ls son[0][rt]
#define rs son[1][rt]
#define new_edge(a,b,c) edge[tot].t = b , edge[tot].v = c , edge[tot].next = head[a] , head[a] = tot ++
using namespace std;

const int maxn = 111111 ;
int son[2][maxn] , fa[maxn] , size[maxn] ;
int val[maxn] , sum[maxn] ;
int parent[maxn] ;

struct Edge {
    int t , next , v ;
} edge[maxn<<1] ;
int tot , head[maxn] ;

void push_down ( int rt ) {
}

void push_up ( int rt ) {
    size[rt] = size[rs] + size[ls] + 1 ;
    sum[rt] = sum[rs] + sum[ls] + val[rt] ;
}

void rot ( int rt , int c ) {
    int y = fa[rt] , z = fa[y] ;
    parent[rt] = parent[y] ;
    push_down (y) ; push_down (rt) ;
    son[!c][y] = son[c][rt] ; fa[son[c][rt]] = y ;
    fa[y] = rt ; son[c][rt] = y ;
    if ( y == son[0][z] ) son[0][z] = rt ;
    else son[1][z] = rt ;
    fa[rt] = z ;
    push_up ( y ) ;
}

void splay ( int rt , int t ) {
    push_down ( rt ) ;
    while ( fa[rt] != t ) {
        if ( fa[fa[rt]] == t ) rot ( rt , son[0][fa[rt]] == rt ) ;
        else {
            int y = fa[rt] , z = fa[y] , c = ( son[0][y] == rt ) , d = ( son[0][z] == y ) ;
            if ( c == d ) rot ( y , c ) , rot ( rt , c ) ;
            else rot ( rt , c ) , rot ( rt , d ) ;
        }
    }
    push_up ( rt ) ;
}

void access ( int rt ) {
    for ( int v = 0 ; rt ; rt = parent[rt] ) {
        splay ( rt , 0 ) ;
        fa[rs] = 0 ; parent[rs] = rt ;
        rs = v ; fa[v] = rt ;
        v = rt ;
        push_up ( rt ) ;
    }
}

int count_k ( int rt , int k ) {
    push_down ( rt ) ;
    if ( size[ls] + 1 == k ) return rt ;
    if ( size[ls] >= k ) return count_k ( ls , k ) ;
    return count_k ( rs , k - size[ls] - 1 ) ;
}

int query ( int l , int r , int c ) {
    if ( c == 1 ) return l ;
    int rt , v ;
    access ( r ) ;
    for ( rt = l , v = 0 ; rt ; rt = parent[rt] ) {
        splay ( rt , 0 ) ;
        if ( !parent[rt] ) {
            if ( !c ) return sum[v] + sum[rs] ;
            else {
                if ( rt == l ) return count_k ( rs , c - 1 ) ;
                if ( size[v] + 1 == c ) return rt ;
                if ( size[v] >= c ) return count_k ( v , size[v] - c + 1 ) ;
                return count_k ( rs , c - 1 - size[v] ) ;
            }
        }
        fa[rs] = 0 ; parent[rs] = rt ;
        rs = v ; fa[v] = rt ;
        v = rt ;
        push_up ( rt ) ;
    }
}

void build ( int _val , int u , int v ) {
    size[v] = 1 ;
    son[0][v] = son[1][v] = fa[v] = 0 ;
    parent[v] = u ;
    val[v] = sum[v] = _val ;
}

void dfs ( int u , int fa ) {
    for ( int i = head[u] ; i != -1 ; i = edge[i].next ) {
        int v = edge[i].t ;
        if ( v == fa ) continue ;
        build ( edge[i].v , u , v ) ;
        dfs ( v , u ) ;
    }
}

void init () {
    tot = 0 ;
    memset ( head , -1 , sizeof ( head ) ) ;
    build ( 0 , 0 , 1 ) ;
}

int main() {
    int cas ; char op[11] ;
    scanf ( "%d" , &cas ) ;
    while ( cas -- ) {
        int n , i , j , k , a , b , c ;
        init () ;
        scanf ( "%d" , &n ) ;
        for ( i = 1 ; i < n ; i ++ ) {
            scanf ( "%d%d%d" , &a , &b , &c ) ;
            new_edge ( a , b , c ) ;
            new_edge ( b , a , c ) ;
        }
        dfs ( 1 , 1 ) ;
        while (scanf ( "%s" , op ) && op[1] != 'O' ) {
            if ( op[1] == 'I' ) {
                scanf ( "%d%d" , &a , &b ) ;
                if ( a == b ) printf ( "0\n" ) ;
                else printf ( "%d\n" , query ( a , b , 0 ) ) ;
            }
            else if ( op[1] == 'T' ) {
                scanf ( "%d%d%d" , &a , &b , &c ) ;
                printf ( "%d\n" , query ( a , b , c ) ) ;
            }
            else break ;
        }
        puts ( "" ) ;
    }
    return 0;
}



你可能感兴趣的:(Link-Cut-Tree)