首页 > 代码库 > HDU4605---Magic Ball Game(主席树 好题)

HDU4605---Magic Ball Game(主席树 好题)

题意:一颗二叉树,任意节点要么有两个孩子要么没孩子。

然后有一个球,从结点1开始往子孙结点走。

每碰到一个结点,有三种情况

如果此球重量等于该结点重量,球就停下了

如果此球重量小于该结点重量,则分别往左右儿子走的可能都是1/2

如果此球重量大于该结点重量,则走向左儿子的概率是1/8,右儿子的概率是7/8

然后若干个询问(10^5次),问一个重量为x的球经过结点v的概率

观察路径,可以发现路径可以分成两种,向左走的路径和向右走的路径,分成这两种是因为各自的计算公式,在向左走的路径中,设大于x的点权有a个,小于x的点权有b个,同理定义c d,我们只需要求出a b c d 就可以了。

做法:

貌似很多做法,,我是用主席树多的,对于节点V,建立根节点1到V的前缀线段树,(此过程bfs实现)利用主席树的性质。

然后主席树里面存两个信息,一个是向左走的一个是向右走的。(此题一些细节,二分的时候不注意的话就会一直wa)

  1 #include <cstdio>  2 #include <cstdlib>  3 #include <algorithm>  4 #include <queue>  5 #include <cstring>  6 using namespace std;  7   8 const int maxn = 1e5+10;  9 struct Edge 10 { 11     int to,next,kind; 12 } e[maxn<<1]; 13 int head[maxn],edge_idx; 14 void add_edge(int x,int y,int kind) 15 { 16     e[edge_idx].to = y; 17     e[edge_idx].next = head[x]; 18     e[edge_idx].kind = kind; 19     head[x] = edge_idx++; 20 } 21 //---------------------------------- 22 int lcnt[maxn*30],rcnt[maxn*30],lson[maxn*30],rson[maxn*30]; 23 int tree[maxn<<1],tot,tree_max; 24 int build (int l,int r) 25 { 26     int root = tot++; 27     lcnt[root] = rcnt[root] = 0; 28     if (l != r) 29     { 30         int mid = (l + r) >> 1; 31         lson[root] = build(l,mid); 32         rson[root] = build(mid+1,r); 33     } 34     return root; 35 } 36 int update (int root,int pos,int lval,int rval) 37 { 38     int newroot = tot++; 39     int tmp = newroot; 40     int l = 1,r = tree_max; 41     lcnt[newroot] = lcnt[root] + lval; 42     rcnt[newroot] = rcnt[root] + rval; 43     while (l < r) 44     { 45         int mid = (l + r) >> 1; 46         if (pos <= mid) 47         { 48             r = mid; 49             rson[newroot] = rson[root]; 50             root = lson[root]; 51             lson[newroot] = tot++; 52             newroot = lson[newroot]; 53         } 54         else 55         { 56             l = mid + 1; 57             lson[newroot] =lson[root]; 58             root = rson[root]; 59             rson[newroot] = tot++; 60             newroot = rson[newroot]; 61         } 62         lcnt[newroot] = lcnt[root] + lval; 63         rcnt[newroot] = rcnt[root] + rval; 64     } 65     return tmp; 66 } 67 int query(int root,int l,int r,int ua,int ub,int kind) 68 { 69     if (ub < ua) 70         return 0; 71     if (ua <= l && ub >= r) 72     { 73         if (kind) 74             return rcnt[root]; 75         else 76             return lcnt[root]; 77     } 78     int mid = (l + r) >> 1; 79     int t1 = 0, t2 = 0; 80     if (ua <= mid) 81         t1 = query(lson[root],l,mid,ua,ub,kind); 82     if (ub > mid) 83         t2 = query(rson[root],mid+1,r,ua,ub,kind); 84     return t1 + t2; 85 } 86  87 int W[maxn],vec[maxn],idx; 88 int hash_(int x) 89 { 90     return lower_bound(vec,vec+idx,x) - vec + 1; 91 } 92 void init() 93 { 94     memset(head,-1,sizeof(head)); 95     idx = tot = 0; 96     edge_idx = 0; 97 } 98 int main(void) 99 {100 #ifndef ONLINE_JUDGE101     freopen("in.txt","r",stdin);102 #endif103     int T;104     scanf ("%d",&T);105     while (T--)106     {107         init();108         int n,q,m;109         scanf ("%d",&n);110         for (int i = 0; i < n ; i++)111         {112             scanf ("%d",W+i+1);113             vec[idx++] = W[i+1];114         }115         sort(vec,vec+idx);116         idx = unique(vec,vec+idx) - vec;117         scanf ("%d",&m);118         for (int i = 0; i < m; i++)119         {120             int x,lf,rg;121             scanf ("%d%d%d",&x,&lf,&rg);122             add_edge(x,lf,0);123             add_edge(x,rg,1);124         }125         tree_max = n;126         tree[1] = build(1,n);127 128         queue<int>Q;129         while (!Q.empty())130             Q.pop();131         Q.push(1);132         while (!Q.empty())133         {134             int x = Q.front();135             Q.pop();136             for (int i = head[x]; ~i; i = e[i].next)137             {138                 int v,k;139                 v = e[i].to, k = e[i].kind;140                 tree[v] = update(tree[x],hash_(W[x]),k == 0, k == 1);141                 Q.push(v);142             }143         }144         scanf ("%d",&q);145         for (int i = 0; i < q; i++)146         {147             int x,v;148             scanf ("%d%d",&v,&x);149             if (v == 1)150             {151                 printf("0 0\n");152                 continue;153             }154             int tmp = x;             //155             x = hash_(x);            // 二分得到的值可能原数组并不存在156             int ua = x-1, ub = x;   //理论上要查询x+1,但是如果tmp在原数组中不存在,那么就不用+1了157             int flag = 0;158             flag = query(tree[v],1,n,x,x,0) + query(tree[v],1,n,x,x,1);159             if (vec[x-1] == tmp)160             {161                 if (flag)162                 {163                     printf("0\n");164                     continue;165                 }166                 ub++;167             }168             int lf_small = query(tree[v], 1, n, 1,   ua, 0);169             int lf_big   = query(tree[v], 1, n, ub, n,   0);170             int rg_small = query(tree[v], 1, n, 1,   ua, 1);171             int rg_big   = query(tree[v], 1, n, ub, n,   1);172             int ans1 = 0, ans2 = 0;173             ans1 += rg_small;174             ans2 += 3*(rg_small+lf_small) + rg_big + lf_big;175             printf("%d %d\n",ans1,ans2);176         }177     }178     return 0;179 }

 

HDU4605---Magic Ball Game(主席树 好题)