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_JUDGE

101     freopen("in.txt","r",stdin);

102 #endif

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

 

你可能感兴趣的:(game)