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

来源:互联网 发布:apache怎么配置 编辑:程序博客网 时间:2024/06/06 05:00

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

当时我看了下题,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 ;}


原创粉丝点击