HDU 4605 (13年多校第一场1006)

21 篇文章 0 订阅
4 篇文章 0 订阅

当时比赛的时候,队友一读完题就叫我看这道,目测就是数据结构。

当时我看了下题,YY了下算法,以为直接从当前点一直往上搜,找到根节点就可以了,因为我突然SB了一下,最近做平衡树的题目做多了,脑子里一下子就想到树的高度是logN的 。然后YY了一下MlogN肯定能过。。。

然后TLE就开始了,后来突然发现这又不是二叉搜索树,极端数据肯定有高度为N/2的。那我就SB了。

真是审题太不仔细了,其实想想也能想到,半天都没人做这道题,怎么可能这么水,也怪当时我脑子抽到了。

还好及时换题了。当时比赛的时候没搞出来,赛后看了标程一知半解的,还好神牛在DISCUSS里面指点了一下。

总算是写出来了。

题意:

给你一棵二叉树,每个节点上都有一个值。

然后对于每次询问,对于一个球 (pos , weight),球的目标是到达pos ,球的重量为weight ,球从根节点开始往下走。

如果当前节点的值大于球的重量,那么往两边走的概率都是1/2。

如果当前节点的值小于球的重量,那么球往左边走的概率是1/8,右边走的概率是7/8。

如果两者相等,那么球就会停在该节点上。

最后输出从根节点到pos的概率,用(7 ^ x) / ( 2 ^ y) 表示,最后输出x , y 即可。


思路:

dfs+树状数组。

首先,我们对树的节点的值和球的重量进行离散化,这里就不多赘述了。

这里我们要维护两个树状数组,分别存所有的左子树,和右子树,用TL[] 和 TR[] 来表示 。

对于每次dfs到的点,先查询这个点上的询问,记录下四个值。LS,LB,RS,RB,分别代表左子树小于当前值的节点数,左子树大于当前值的节点数,右子树小于当前值的节点数,右子树大于当前值的节点树。

因为我们很容易得到(7 ^ x)的值一定是往右子树上走并且当前节点值小于球的重量,所以x的值就等于RS的值。

同理(2 ^ y)  , y的值就是(LB + RB + 3 *(LS + RS) )。 

所以,每次询问的时候,我们只要记录下这四个值就可以了。

用树状数组就可以在logN的时间内求出这些值。

当dfs到这个点时,我们将这个点插入到树状数组,即在这个点的位置add(1),因为所有的数据已经离散化了,所以可以算出N最大为20W。

讲的太烂了,代码如下。。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstring>
#include <queue>
#include <set>
#include <vector>
#include <stack>
#include <map>
#include <iomanip>
#define PI acos(-1.0)
#define Max 2505
#define inf 1<<28
#define LL(x) ( x << 1 )
#define RR(x) ( x << 1 | 1 )
#define REP(i,s,t) for( int i = ( s ) ; i <= ( t ) ; ++ i )
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
#define mp(a,b) make_pair(a,b)
#define PII pair<int,int>
using namespace std;

/***输入优化***/
inline void RD(int &ret) {
    char c;
    do {
        c = getchar();
    } while(c < '0' || c > '9') ;
    ret = c - '0';
    while((c=getchar()) >= '0' && c <= '9')
        ret = ret * 10 + ( c - '0' );
}
/***变量声明***/
struct kdq {
    int e , id ,next ;
} ed[1111111] ;
int head[111111] ,num = 0 ;
int Ls[211111] ,Lb[211111] ,Rs[211111] ,Rb[211111] ;
int val[111111] ;
int qe[211111] ;//离散化用
vector<int>query[111111] ;
int TL[111111] , TR[111111] ;//树状数组
bool vis[111111] ;
int askpos[111111] ,askweight[111111] ;
int hash[111111] ;
int hash1[111111] ;
int isE[111111] ;
int n ;

/***初始化***/
void init() {
    mem(Ls , 0) ;
    mem(Lb , 0) ;
    mem(Rs , 0) ;
    mem(Rb , 0) ;
    mem(head , -1) ;
    mem(TL , 0) ;
    mem(TR , 0) ;
    mem(isE , 0) ;
    mem(vis , 0) ;
    num = 0 ;
}
void add(int s ,int e ,int id) {
    ed[num].e = e ;
    ed[num].id = id ;
    ed[num].next = head[s] ;
    head[s] = num ++ ;
}
/***树状数组***/
int lowbit(int x) {
    return x & (-x) ;
}

void add(int c[] ,int x ,int num) {
    for (int i = x ; i <= n ; i += lowbit(i)) {
        c[i] += num ;
    }
}
int sum(int c[] ,int x ) {
    int ans = 0 ;
    for (int i = x ; i > 0 ; i -= lowbit(i)) {
        ans += c[i] ;
    }
    return ans ;
}

/***dfs***/
void dfs(int id) {
    /***询问***/
    for (__typeof(query[id].begin()) i = query[id].begin() ; i != query[id].end() ; i ++ ) {
        int tt = hash1[*i] ;
        //cout << *i << endl;
        Ls[*i] = sum(TL ,tt - 1) ;//左子树的前tt - 1项和,即节点值小于val[askpos[*i]]的节点总数。
        Lb[*i] = sum(TL ,n) - sum(TL , tt) ;//节点值大于val[askpos[*i]]的节点总数。
        Rs[*i] = sum(TR , tt - 1) ;//同理
        Rb[*i] = sum(TR , n) - sum(TR , tt ) ;//同理
        //cout << Ls[*i] << " " << Lb[*i] << " " << Rs[*i] << " " << Rb[*i] << endl;
        if(vis[tt]) {
            isE[*i] = 1 ;
        }
    }
    for (int i = head[id] ; ~i ; i = ed[i].next) {
        int e = ed[i].e ;
        int tt = hash[id] ;
        int flag = ed[i].id ;
        if(flag == 1) {//如果是左子树
            add(TL , tt , 1) ;//在TL的tt位置加上1,TL是左子树的树状数组。
        } else {
            add(TR , tt , 1) ;//同理
        }
        vis[tt] = 1 ;
        dfs(e) ;
        if(flag == 1) {
            add(TL , tt, -1 ) ;
        } else {
            add(TR , tt , -1) ;
        }
        vis[tt] = 0 ;
    }
}
/***debug***/
void debughash(int nn ,int pos) {
    if(pos == 0) {
        for (int i = 1 ; i < nn ; i ++ ) {
            cout << hash[i] << " " ;
        }
        cout << endl;
    } else if(pos == 1) {
        for (int i = 1 ; i < nn ; i ++ ) {
            cout << hash1[i] << " " ;
        }
        cout << endl;
    }
}
int main() {
    int T ;
    cin >> T ;
    while ( T -- ) {
        int nn ;
        init() ;
        cin >> nn ;
        int cnt = 0 ;
        int cnt1 = 1 ;
        int cnt2 = 1 ;
        for (int i = 1 ; i <= nn ; i ++ ) {
            RD(val[i]) ;
            qe[cnt ++ ] = val[i] ;
            hash[cnt1 ++ ] = val[i] ;
        }
        int m ;
        cin >> m ;
        /***建树***/
        while(m -- ) {
            int a , b , c ;
            RD(a) ;
            RD(b) ;
            RD(c) ;
            add(a , b , 1) ;//左子树
            add(a , c , 0) ;//右子树
        }
        /***询问***/
        cin >> m ;
        for (int i = 1 ; i <= nn ;i ++ ){
            query[i].clear() ;
        }
        for (int i = 1 ; i <= m ; i ++ ) {
            RD(askpos[i]) ;
            RD(askweight[i]) ;
            query[askpos[i]].push_back(i) ;
            qe[cnt ++ ] = askweight[i] ;
            hash1[cnt2 ++ ] = askweight[i] ;
        }
        /***离散化***/
        sort(qe , qe + cnt) ;
        n = unique(qe , qe + cnt ) - qe ;
        for (int i = 1 ; i < cnt1 ; i ++ ) {
            hash[i] = lower_bound(qe, qe + n , hash[i]) - qe + 1 ;
        }
        for (int i = 1 ; i < cnt2 ; i ++ ) {
            hash1[i] = lower_bound(qe , qe + n ,hash1[i]) - qe + 1 ;
        }
        dfs(1) ;
        for (int i = 1 ; i <= m ; i ++ ) {
            if(isE[i]) {
                puts("0") ;
            } else {
                int a = 3 * Ls[i] + 3 * Rs[i] + Lb[i] + Rb[i] ;
                int b = Rs[i] ;
                printf("%d %d\n", b , a ) ;
            }
        }
    }
    return 0 ;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值