题目大意很简单。
有一颗树(10^5结点),所有结点要么没有子结点,要么有两个子结点。
然后每个结点都有一个重量值,根结点是1
然后有一个球,从结点1开始往子孙结点走。
每碰到一个结点,有三种情况
如果此球重量等于该结点重量,球就停下了
如果此球重量小于该结点重量,则分别往左右儿子走的可能都是1/2
如果此球重量大于该结点重量,则走向左儿子的概率是1/8,右儿子的概率是7/8
有一颗树(10^5结点),所有结点要么没有子结点,要么有两个子结点。
然后每个结点都有一个重量值,根结点是1
然后有一个球,从结点1开始往子孙结点走。
每碰到一个结点,有三种情况
如果此球重量等于该结点重量,球就停下了
如果此球重量小于该结点重量,则分别往左右儿子走的可能都是1/2
如果此球重量大于该结点重量,则走向左儿子的概率是1/8,右儿子的概率是7/8
然后若干个询问(10^5次),问一个重量为x的球经过结点v的概率
对于从v到根节点(不包括v),假如我们知道 ls (向左走比x小的节点个数)、rs(向右走比x小的节点个数)、lb(向左走比x大的节点个数)、rb(向右走比x大的节点的个数)
那么概率就是 c= (1/2)^ls * (1/8)*lb * (1/2) ^ rs * (7/8)^rb转换成题目要求的输出就是 a=rs,b=3*(rs+ls)+lb+rb;
离线做法:
要求得上述值。可以搜索整颗树,到v点时处理对v点的查询。还需要记录v到root路径上的节点状态,所以要回溯。还需要快速求的从v到根的路径上向左 和 向右 的 重量区间的节点出现个数,就可以用树状数组记录每个重量区间包含多少个节点,因为重量范围很大,所以需要离散化。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn=100008;
int n,q,size;
int v[maxn*2];//节点数值
int sub_v[maxn*2];
int dv[maxn*2];//节点离散化后的数值
int lbit[maxn*4];//bit处理向左走的节点值域
int rbit[maxn*4];//bit处理向右走的节点值域
int X[maxn];
int Y[maxn];
vector<int> query[maxn];//节点的查询
vector<int> g[maxn];//树节点
void add_edge(int u,int v)
{
g[u].push_back(v);
}
void init()
{
for(int i=0;i<maxn;++i)
{
g[i].clear();
query[i].clear();
}
}
void init_bit()
{
memset(lbit,0,sizeof(lbit));
memset(rbit,0,sizeof(rbit));
}
int lowbit(int x)
{
return x&(-x);
}
void add(int k,int num,int which)
{
while(k<=size)
{
if(!which) lbit[k]+=num;
else rbit[k]+=num;
k+=lowbit(k);
}
}
int read(int k,int which)
{
int sum=0;
while(k)
{
if(!which)
sum+=lbit[k];
else sum+=rbit[k];
k-=lowbit(k);
}
return sum;
}
void dfs(int u,int lct,int rct)
{
for(int i=0;i<query[u].size();++i)
{
int num=query[u][i],x=dv[n+num];
// printf("%d\n", read(x,0)-read(x-1,0));
// printf("%d\n", read(x,1)-read(x-1,1));
if((read(x,0)-read(x-1,0))||(read(x,1)-read(x-1,1)))
{
X[num]=-1;
continue;
}
int ls=read(x,0),rs=read(x,1);
int lb=read(size,0)-read(x,0),rb=read(size,1)-read(x,1);
X[num]=rs,Y[num]=3*(rs+ls)+lb+rb;
}
if(g[u].size())
{
int dt=dv[u];
//向左移动
add(dt,1,0),dfs(g[u][0],lct+1,rct),add(dt,-1,0);
//向右移动
add(dt,1,1),dfs(g[u][1],lct,rct+1),add(dt,-1,1);
}
}
void discretize()
{
int _n=n+q;
for(int i=1;i<=_n;++i)
sub_v[i]=v[i];
sort(sub_v+1,sub_v+_n+1);
size=unique(sub_v+1,sub_v+_n+1)-sub_v-1;
for(int i=1;i<=_n;++i)
dv[i]=lower_bound(sub_v+1,sub_v+size+1,v[i])-sub_v;
}
void solve()
{
init_bit();
discretize();
dfs(1,0,0);
for(int i=1;i<=q;++i)
{
if(X[i]==-1)
printf("0\n");
else printf("%d %d\n",X[i],Y[i]);
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
init();
scanf("%d",&n);
for(int i=1;i<=n;++i)
scanf("%d",v+i);
int m,u,a,b;
scanf("%d",&m);
for(int i=0;i<m;++i)
{
scanf("%d%d%d",&u,&a,&b);
add_edge(u,a),add_edge(u,b);
}
int x,vn;
scanf("%d",&q);
for(int i=1;i<=q;++i)
{
scanf("%d%d",&vn,&x);
v[n+i]=x;
query[vn].push_back(i);
}
solve();
}
return 0;
}