【HDU】5796 Magic Number【lca】

题目链接:Magic Number

看懂题目,就知道怎么做

#include <stdio.h>
#include <vector>
#include <string.h>
#include <algorithm>
using namespace std ;

typedef long long LL ;
typedef pair < int , int > pii ;

#define clr( a , x ) memset ( a , x , sizeof a )

const int MAXN = 5005 ;
const int N = 1000005 ;

int n , m , q ;
int a[MAXN] , b[MAXN] , c[N] ;
int f[MAXN][15] , dep[MAXN] ;
int dfn[MAXN] , dfs_time ;
vector < int > G[MAXN] ;

int lca ( int x , int y ) {
    if ( dep[x] < dep[y] ) swap ( x , y ) ;
    for ( int i = 14 ; ~i ; -- i ) {
        if ( dep[x] - ( 1 << i ) >= dep[y] ) x = f[x][i] ;
    }
    if ( x == y ) return x ;
    for ( int i = 14 ; ~i ; -- i ) {
        if ( ~f[x][i] && ~f[y][i] && f[x][i] != f[y][i] ) {
            x = f[x][i] ;
            y = f[y][i] ;
        }
    }
    return f[x][0] ;
}

void dfs ( int u ) {
    dfn[u] = ++ dfs_time ;
    for ( int i = 0 ; i < G[u].size () ; ++ i ) {
        dfs ( G[u][i] ) ;
    }
}

int cmp ( const int& a , const int& b ) {
    return dfn[a] < dfn[b] ;
}

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 () {
    clr ( f , -1 ) ;
    dfs_time = 0 ;
    scanf ( "%d%d" , &n , &m ) ;
    for ( int i = 1 ; i <= n ; ++ i ) {
        G[i].clear () ;
    }
    for ( int i = 1 ; i <= m ; ++ i ) {
        scanf ( a[i] ) ;
        a[i] ++ ;
    }
    sort ( a + 1 , a + m + 1 ) ;
    int j = 1 ;
    for ( int i = 1 ; i <= n ; ++ i ) {
        int x = -1 , l = i * ( i - 1 ) / 2 + 1 , r = i * ( i + 1 ) / 2 ;
        while ( j <= m && a[j] <= r ) {
            int t = a[j ++] - l + 1 ;
            if ( t >= i ) continue ;
            if ( x == -1 ) x = t ;
            else x = lca ( x , t ) ;
        }
        if ( x == -1 ) x = 0 ;
        dep[i] = dep[x] + 1 ;
        f[i][0] = x ;
        G[x].push_back ( i ) ;
        for ( int j = 1 ; j < 15 ; ++ j ) {
            if ( ~f[i][j - 1] ) f[i][j] = f[f[i][j - 1]][j - 1] ;
        }
    }
    dfs ( 0 ) ;
    scanf ( "%d%d" , &q , &m ) ;
    for ( int i = 1 ; i <= q ; ++ i ) {
        scanf ( b[i] ) ;
    }
    for ( int i = 1 ; i <= m ; ++ i ) {
        scanf ( c[i] ) ;
        c[i] ++ ;
    }
    sort ( c + 1 , c + m + 1 ) ;
    int tot = 0 ;
    j = 1 ;
    for ( int i = 1 ; i <= q ; ++ i ) {
        int l = tot + 1 , r = tot + b[i] , n1 = 0 ;
        while ( j <= m && c[j] <= r ) {
            int t = c[j ++] - l + 1 ;
            if ( t <= n ) a[n1 ++] = t ;
        }
        sort ( a , a + n1 , cmp ) ;
        int ans = 0 ;
        for ( int j = 0 ; j < n1 ; ++ j ) {
            ans += dep[a[j]] ;
            if ( j ) ans -= dep[lca ( a[j - 1] , a[j] )] ;
        }
        printf ( "%d\n" , ans ) ;
        tot += b[i] ;
    }
}

int main () {
    int T ;
    scanf ( "%d" , &T ) ;
    for ( int i = 1 ; i <= T ; ++ i ) {
        printf ( "Case #%d:\n" , i ) ;
        solve () ;
    }
    return 0 ;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值