题意:
给你一棵二叉树,每个节点上都有一个值。
然后对于每次询问,对于一个球 (pos , weight),球的目标是到达pos ,球的重量为weight ,球从根节点开始往下走。
如果当前节点的值大于球的重量,那么往两边走的概率都是1/2。
如果当前节点的值小于球的重量,那么球往左边走的概率是1/8,右边走的概率是7/8。
如果两者相等,那么球就会停在该节点上。
最后输出从根节点到pos的概率,用(7 ^ x) / ( 2 ^ y) 表示,最后输出x , y 即可。
思路:DFS + 树状数组
很自然的想法是,每次从根找v,dfs算出概率,这样复杂度是nlogn,会超时。
从根到每个节点的路径是唯一的,那么是需要统计出向左比x大的,向左比x小的,向右比x大的,向右比x小的。设这条路径向左孩子节点走的节点的权值比x大的有ld个,比x小的有lx个,向右孩子节点走的节点的权值比x大的有rd个,比x小的有rx个,概率为(1/2)^ld * (1/8)^lx * (1/2)^rd * (7/8)^rx。
得 x= rd,y = ld + rd+ (lx + rx) * 3。统计个数用树状数组。注意当路径中有=x的节点时,这个节点永远无法到达。dfs保证了每次处理的都是一条从根出发的路径,不受孩子节点的影响。
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int maxn = 1e5+5;
using namespace std;
int n, m, q;
int LC[maxn], RC[maxn]; // leftchild, rightchild
int w[maxn], tmp[maxn*2], ansx[maxn], ansy[maxn], C[2][maxn];
vector<int> v1[maxn], v2[maxn];
inline int lowbit(int x){return x & -x;}
void add(int u, int x, int v){for(int i = x; i < maxn; i+= lowbit(i)) C[u][i]+= v;}
int sum(int u, int x){
int s = 0;
for(int i = x; i > 0; i-= lowbit(i)) s+= C[u][i];
return s;
}
void dfs(int u){
for(int i = 0; i < v1[u].size(); ++i){
int a = v1[u][i], x = v2[u][i];
int ltot = sum(0, maxn-1); // 左边总共
int rtot = sum(1, maxn-1);
int lx = sum(0, x-1); // 左边比x小的个数
int rx = sum(1, x-1);
int ld = sum(0, maxn-1) - sum(0, x); // 左边比x大的个数
int rd = sum(1, maxn-1) - sum(1, x);
if(ld + lx != ltot||rd + rx != rtot){
ansx[a] = -1; ansy[a] = -1;
continue;
}
ansx[a] = rx;
ansy[a] = ld + rd + 3*(lx + rx);
}
if(LC[u] != -1){ // 按照题意,有左孩子就一定有右孩子
add(0, w[u], 1);
dfs(LC[u]);
add(0, w[u], -1);
add(1, w[u], 1);
dfs(RC[u]);
add(1, w[u], -1);
}
}
int main()
{
//freopen("in.txt","r",stdin);
int T; scanf("%d",&T);
while(T--){
memset(LC, -1, sizeof(LC));
memset(C, 0, sizeof(C));
scanf("%d",&n);
for(int i = 1; i <= n; ++i){
scanf("%d",&w[i]);
tmp[i] = w[i];
v1[i].clear(); v2[i].clear();
}
scanf("%d",&m);
for(int i = 0; i < m; ++i){
int u,a,b; scanf("%d%d%d",&u,&a,&b);
LC[u] = a;
RC[u] = b;
}
int cnt = n;
scanf("%d",&q);
for(int i = 0; i < q; ++i){
int v,x; scanf("%d%d",&v,&x);
v1[v].push_back(i);
v2[v].push_back(x);
tmp[++cnt] = x;
}
// 数据范围到1e9,所以要离散化
sort(tmp+1, tmp+cnt+1);
int n2 = unique(tmp+1, tmp+cnt+1) - tmp - 1; // 去重
for(int i = 1; i <= n; ++i){ // 按照大小重新分配权值,即离散化
w[i] = lower_bound(tmp+1, tmp+n2+1, w[i]) - tmp;
for(int j = 0; j < v2[i].size(); ++j) v2[i][j] = lower_bound(tmp+1, tmp+n2+1, v2[i][j]) - tmp;
}
dfs(1);
for(int i = 0; i < q; ++i){
if(ansx[i] == -1) printf("0\n");
else printf("%d %d\n", ansx[i],ansy[i]);
}
}
fclose(stdin);
return 0;
}