然后若干个询问(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; }