题意:有T组测试数据,N表示这棵树有N个点,下一行的N个数,表示每个点的权值W,M表示边的关系,接下来的M行,每行有三个数字,u,b,b,表示点a和点b分别是点u的左儿子和右儿子。Q表示查询数,接下来的Q行,每行两个数字,v和X。
一个权值为X球从根节点开始下落,每落到一个节点的时候,1.如果X=W[i],或者没有儿子节点了,球停止下落。2.如果X<W[i],球各有1/2的概率落到左右儿子节点。3.如果X>W[i],球有1/8的概率落到左儿子,有7/8的概率落到右儿子。问球落到点v的概率是多少(概率用7^x/2^y表示,即输出x和y就可以)?
以上复制与shiqi_614大牛关于这道题的描述。
做法我研究了许久才弄懂,一开始直接用线段树的结构去从那个点往上走,后来发觉这不是一个完全二叉树。。
做法是把树的每条链用树状数组去维护,DFS这颗树,用一种类似回朔的办法。对于权值离散化,我用的是map映射,走到某个节点,如果要往左边走,就把这个节点权值加1加入第一颗树状数组,往右走就加入第二颗,如果当前节点有询问,直接用lower_bound找到>=x的第一个值如果这个值等于x且sum(pos,0)-sum(pos-1,0)或者sum(pos,1)-sum(pos-1,1)>=1那么就说明这条链上有等于x的,就不可达到。不然就统计前缀和,代表前面有几个小于x的值,以及可以算出后面有几个大于x的值,然后计算既可。
AC代码:
#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<ctype.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdlib>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#include<ctime>
#include<string.h>
#include<string>
#include<bitset>
using namespace std;
#define ll __int64
#define eps 1e-8
#define NMAX 100000+10
template<class T>
inline void scan_d(T &ret)
{
char c;
int flag = 0;
ret=0;
while(((c=getchar())<'0'||c>'9')&&c!='-');
if(c == '-')
{
flag = 1;
c = getchar();
}
while(c>='0'&&c<='9') ret=ret*10+(c-'0'),c=getchar();
if(flag) ret = -ret;
}
int w[NMAX],a[2][NMAX],G[NMAX][2],wei[NMAX],nct,ans[NMAX][2];
map<int,int>mp;
vector<pair<int, int > >v[NMAX];
int lowbit(int x)
{
return x&(-x);
}
int sum(int x, int flag)
{
int ret = 0;
while(x > 0)
{
ret += a[flag][x];
x -= lowbit(x);
}
return ret;
}
void add(int x, int d, int flag)
{
while(x <= nct)
{
a[flag][x] += d;
x += lowbit(x);
}
}
map<int,int>::iterator it;
void dfs(int pos)
{
int sz = v[pos].size();
for(int i = 0; i < sz; i++)
{
int x = v[pos][i].second,k = v[pos][i].first,pp;
it = mp.lower_bound(x);//第一个>=x的
if(it == mp.end()) pp = nct+1;
else pp = it->second;
int t1 = sum(pp,0)-sum(pp-1,0),t2 = sum(pp,1)-sum(pp-1,1);
if(it->first == x && (t1 >= 1 || t2 >= 1))
{
ans[k][0] = -1;
continue;
}
t1 = sum(pp-1,0); t2 = sum(pp-1,1);
int t3 = sum(nct,0)-t1, t4 = sum(nct,1)-t2;
// cout<<x<<" "<<pp<<" "<<t1<<" "<<t2<<" "<<t3<<" "<<t4<<endl;
ans[k][0] = t2;
ans[k][1] = 3*t1+3*t2+t3+t4;
}
if(G[pos][0] == 0) return;
add(mp[w[pos]],1,0);
dfs(G[pos][0]);
add(mp[w[pos]],-1,0);
add(mp[w[pos]],1,1);
dfs(G[pos][1]);
add(mp[w[pos]],-1,1);
}
int main()
{
#ifdef GLQ
freopen("input.txt","r",stdin);
// freopen("o4.txt","w",stdout);
#endif // GLQ
int t,n,m,q,i,j;
scanf("%d",&t);
while(t--)
{
mp.clear();
memset(a,0,sizeof(a));
scanf("%d",&n);
for(i = 1; i <= n; i++)
scanf("%d",&w[i]);
scanf("%d",&m);
memset(G,0,sizeof(G));
for(i = 0; i < m; i++)
{
int temp;
scanf("%d",&temp);
scanf("%d%d",&G[temp][0],&G[temp][1]);
}
memcpy(wei,w,sizeof(w));
sort(wei+1,wei+1+n);
nct = unique(wei+1,wei+n+1)-wei-1;
for(i = 1; i <= nct; i++)
mp[wei[i]] = i;
scanf("%d",&q);
for(i = 1; i <= n; i++) v[i].clear();
for(i = 0; i < q; i++)
{
int p,x;
scanf("%d%d",&p,&x);
v[p].push_back(make_pair(i,x));
}
dfs(1);
for(i = 0; i < q; i++)
if(ans[i][0] == -1) printf("0\n");
else printf("%d %d\n",ans[i][0],ans[i][1]);
}
return 0;
}