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; }