题目大意很简单。
有一颗树(10^5结点),所有结点要么没有子结点,要么有两个子结点。然后每个结点都有一个重量值,根结点是1
然后有一个球,从结点1开始往子孙结点走。
每碰到一个结点,有三种情况
如果此球重量等于该结点重量,球就停下了
如果此球重量小于该结点重量,则分别往左右儿子走的可能都是1/2
如果此球重量大于该结点重量,则走向左儿子的概率是1/8,右儿子的概率是7/8
然后若干个询问(10^5次),问一个重量为x的球经过结点v的概率
仔细想一下,一个球走到某个结点,路径已经是固定的了,但是暴力肯定会超时,那么观察路径,可以发现路径可以分成两种,向左走的路径和向右走的路 径,分成这两种的原因也是因为各自的计算公式,在向左走的路径中,设大于x的点权有a个,小于x的点权有b个,那么向左走的路径概率就是p1= (1/2)^a * (1/8) ^b, 同理向右的路径中概率
p2 = (1/2)^c * (7/8) ^d,最后二者相乘即是答案。
p1*p2则分母的指数就是d,分子的指数即为d/(a+c+3*b+3*d)
需要注意的是,如果从1到该点的路径中有一个点的重量等于x,那么这个点是永远被达不到的。
用树状数组维护指数即可
1 #pragma comment(linker, "/STACK:1024000000,1024000000") 2 #include <stdio.h> 3 #include <string.h> 4 #include <algorithm> 5 #include <iostream> 6 #include <map> 7 #include <vector> 8 using namespace std; 9 const int MAXN=400010; 10 int next[MAXN][2]; 11 int n; 12 int root; 13 int w[MAXN]; 14 struct QQ 15 { 16 int v; 17 int X; 18 int ans1,ans2; 19 }Query[MAXN]; 20 vector<int>vec[MAXN]; 21 bool used[MAXN]; 22 int a[MAXN]; 23 map<int,int>mp; 24 25 int c1[MAXN]; 26 int c2[MAXN]; 27 int t; 28 int lowbit(int x) 29 { 30 return x&(-x); 31 } 32 void add1(int i,int val) 33 { 34 while(i <= t) 35 { 36 c1[i] += val; 37 i += lowbit(i); 38 } 39 } 40 int sum1(int i) 41 { 42 int s = 0; 43 while(i > 0) 44 { 45 s += c1[i]; 46 i -= lowbit(i); 47 } 48 return s; 49 } 50 void add2(int i,int val) 51 { 52 while(i <= t) 53 { 54 c2[i] += val; 55 i += lowbit(i); 56 } 57 } 58 int sum2(int i) 59 { 60 int s = 0; 61 while(i > 0) 62 { 63 s += c2[i]; 64 i -= lowbit(i); 65 } 66 return s; 67 } 68 69 void dfs(int u) 70 { 71 int sz = vec[u].size(); 72 for(int i = 0;i < sz;i++) //对于每个点上的询问 73 { 74 int id = vec[u][i]; 75 int X = mp[Query[id].X]; 76 if(sum1(X)-sum1(X-1)!=0 || sum2(X)-sum2(X-1)!=0) 77 { 78 Query[id].ans1 = Query[id].ans2 = -1; 79 } 80 else 81 { 82 Query[id].ans1 = Query[id].ans2 = 0; 83 Query[id].ans2 += 3*sum1(X-1)+sum1(t)-sum1(X); 84 Query[id].ans1 += sum2(X-1); 85 Query[id].ans2 += 3*sum2(X-1)+sum2(t)-sum2(X); 86 } 87 } 88 if(next[u][0]==0 && next[u][1]==0)return; 89 add1(mp[w[u]],1); //保证是有序的 90 dfs(next[u][0]); //左走 91 add1(mp[w[u]],-1); //恢复 92 add2(mp[w[u]],1); //右走 93 dfs(next[u][1]); 94 add2(mp[w[u]],-1); //回溯法 95 } 96 97 int main() 98 { 99 //freopen("in.txt","r",stdin); 100 //freopen("out.txt","w",stdout); 101 int T; 102 int m; 103 int u,x,y; 104 scanf("%d",&T); 105 while(T--) 106 { 107 scanf("%d",&n); 108 for(int i = 1;i <= n;i++) 109 { 110 used[i] = false; 111 next[i][0] = next[i][1] = 0; 112 vec[i].clear(); 113 } 114 t = 0; 115 for(int i = 1;i <= n;i++) 116 { 117 scanf("%d",&w[i]); 118 a[t++] = w[i]; 119 } 120 scanf("%d",&m); 121 while(m--) 122 { 123 scanf("%d%d%d",&u,&x,&y); 124 used[x] = true; 125 used[y] = true; 126 next[u][0] = x; 127 next[u][1] = y; 128 } 129 scanf("%d",&m); 130 for(int i = 0;i < m;i++) 131 { 132 scanf("%d%d",&u,&x); 133 Query[i].v = u; 134 Query[i].X = x; 135 a[t++] = x; 136 vec[u].push_back(i); 137 } 138 for(int i = 1;i <= n;i++) 139 if(!used[i]) 140 { 141 root = i; 142 break; 143 } 144 sort(a,a+t); 145 t = unique(a,a+t)-a; 146 mp.clear(); 147 for(int i = 0;i < t;i++) 148 mp[a[i]]=i+1; 149 memset(c1,0,sizeof(c1)); 150 memset(c2,0,sizeof(c2)); 151 dfs(root); 152 for(int i = 0;i < m;i++) 153 { 154 if(Query[i].ans1 == -1) 155 printf("0 "); 156 else printf("%d %d ",Query[i].ans1,Query[i].ans2); 157 } 158 } 159 return 0; 160 }