hdu4605 magic ball game 树状数组+离线处理

时间:2023-03-08 16:16:39

题意:给你一棵二叉树,每个节点有一个w值,现在有一颗小球,值为x,从根节点往下掉,如果w==x,那么它就会停止;如果w>x,那么它往左、右儿子的概率都是1、2;如果w<x,那么它往左儿子的概率是1/8,右儿子是7/8。现在给你q个询问,问你值为x的球道达节点u的概率为多少。

连接:http://acm.hdu.edu.cn/showproblem.php?pid=4605

思路:节点和询问比较多,可以储存询问集中处理。将所有的询问集中起来,与被询问的节点放在一起一起走,让所有节点的W值与被询问的W值都存起来排序,这样走过的节点设置为1没走过的为0这样就可以知道谁比他大谁比他小,另外设两个数组就可以知道是走了右边还是左边,这样线段树和树状数组都可以求解。

用宝哥的话说最后的答案就是:从一根节点u到一个点v存在的是唯一的一条确定的道路。我们只需要它在这条路上往左拐的情况中w的值(X可能大于该点的权值grtL,可能小于该点的权值lessL) 往右拐的情况中w的值(X可能大于该点的权值grtR,可能小于该点的权值lessR)  那么对于这个点的询问我们就可以知道:
x = grtR(只有它对7有贡献)  y = (lessL + lessR) + (grtL + grtR)*3;

代码:(用g++ac,叫c++的话加上 #pragma comment(linker, "/STACK:1024000000,1024000000")

注意离散处理一下,让bsearch中不会出现相同的值,假设好多树节点的值相同,只需要+1即可。树状数组存的就是出现次数。

 #include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <queue>
#include <vector>
#define cl(a,b) memset(a,b,sizeof(a))
#define loop(s,i,n) for(i = s;i < n;i++) const int maxn = ;
using namespace std;
struct ask
{
int num,turn;
};
struct node
{
int num,l,r;
}g[maxn];
int a[maxn*];
int b[maxn*];
int num[maxn*];
int suml[maxn*];
int sumr[maxn*];
vector<ask>q[maxn];
int ans[maxn][];
int cnt;
int lowbit(int x)
{
return x&-x;
}
int sumleft(int x)
{
int ret;
ret = ;
while(x > )
{
ret += suml[x];
x-= lowbit(x);
}
return ret;
} int sumright(int x)
{
int ret;
ret = ;
while(x > )
{
ret += sumr[x];
x-= lowbit(x);
}
return ret;
}
void addl(int x,int d)
{
while(x <= cnt)
{
suml[x] += d;
x += lowbit(x);
}
} void addr(int x,int d)
{
while(x <= cnt)
{
sumr[x] += d;
x += lowbit(x);
}
}
int bsearch(int key)
{
int l,r,mid;
l = ;
r = cnt;
while(l <= r)
{
mid = (l+r)/;
if(b[mid] == key) return mid;
if(key < b[mid]) r = mid-;
else l = mid+;
}
return ;
}
void dfs(int rt)
{
int i;
int t,loc;
for(i = ;i < q[rt].size();i++)
{ t = q[rt][i].num;
loc = bsearch(t);
if(a[loc] > )
{
ans[q[rt][i].turn][] = -;
ans[q[rt][i].turn][] = -; }
else{
ans[q[rt][i].turn][] = sumright(loc);
ans[q[rt][i].turn][] = *sumleft(loc)+sumleft(cnt)-sumleft(loc)+*sumright(loc)+sumright(cnt)-sumright(loc);
} }
loc = bsearch(g[rt].num);
if(g[rt].l)
{
addl(loc,);
a[loc]++;
dfs(g[rt].l);
addl(loc,-);
a[loc]--;
}
if(g[rt].r){
addr(loc,);
a[loc]++;
dfs(g[rt].r);
addr(loc,-);
a[loc]--;
}
return ; }
int main()
{
int t;
cin>>t;
while(t--)
{
int m,n;
scanf("%d",&n);
cnt = ;
int i;
memset(sumr,,sizeof(sumr));
cl(suml,);
cl(a,); loop(,i,n+)
scanf("%d",&g[i].num),g[i].l = g[i].r = ,num[cnt] = g[i].num,cnt++,q[i].clear(); scanf("%d",&m);
while(m--)
{
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
g[a].l = b;
g[a].r = c;
}
int k;
scanf("%d",&k);
loop(,i,k+)
{
int tmp,w;
scanf("%d %d",&tmp,&w);
struct ask temp;
temp.num = w;
temp.turn = i;
q[tmp].push_back(temp);
num[cnt++] = w;
}
cnt--; sort(num+,num+cnt+);
int zcnt;
zcnt = ;
num[] = ;
for(i = ;i <= cnt;i++)
{
if(num[i] != num[i-])
b[++zcnt] = num[i];
}
cnt = zcnt;
dfs();
for(i = ;i <= k;i++)
{
if(ans[i][] == - || ans[i][] == -)
{
puts("");
continue;
}
else
{
printf("%d %d\n",ans[i][],ans[i][]);
} } }
return ;
}