题意:给出一棵二叉树,树上每个节点都有一个权值w[i],从根节点向下扔一个权值为x的小球,小球到达每个节点有三种情况:①x==w[u],小球停止运动 ②x<w[u],小球有相同的概率向左或向右走 ③x>w[u],小球有1/8的概率向左走,有7/8的概率向右走。有q个询问,每个询问有两个值v、x,回答从根节点扔小球,小球停在v或经过v的概率。
思路:由于一棵树从根节点到任意一个节点的路径是唯一的,那么我们只要将询问离散化,然后用一个数据结构去维护走过的路径上的权值就行了,没走到一个结点,就回答和这个节点有关的询问。我用的线段树维护,因为小球向左向右走的概率跟该节点的权值和小球的权值有关,那么我们可以维护两颗线段树,一棵是从根节点到v的路径中向左走的节点的权值,一棵是从根节点到v的路径中向右走的节点的权值,然后就可以很简单的查到比小球权值大(小)的节点的个数,答案算起来也不难。走过某一节点后,就把这个节点从所选的数据结构中删掉就行了。当时多校做完以后看了题解没看懂Orz,今天也研究了好半天……但这题果断很好啊
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<map> #include<queue> #include<stack> #include<cmath> #include<vector> #define inf 0x3f3f3f3f #define Inf 0x3FFFFFFFFFFFFFFFLL #define eps 1e-9 #define pi acos(-1.0) #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; typedef long long ll; const int maxn=100000+10; int lson[maxn],rson[maxn],rnk[maxn]; int ans1[maxn],ans2[maxn],ww[maxn]; bool flag[maxn]; int n,m,q,cnt,lf,rn; struct Node { int u,w; bool operator < (const Node &a) const { return w<a.w; } }; Node node[maxn]; vector<Node>querys[maxn]; int maxv[maxn<<1][2],minv[maxn<<1][2],sum[maxn<<1][2]; void Init() { memset(lson,0xff,sizeof(lson)); memset(rson,0xff,sizeof(rson)); memset(flag,0,sizeof(flag)); for(int i=1;i<=n;++i) querys[i].clear(); } void PushUp(int rt,int h) { sum[rt][h]=sum[rt<<1][h]+sum[rt<<1|1][h]; maxv[rt][h]=max(maxv[rt<<1][h],maxv[rt<<1|1][h]); minv[rt][h]=min(minv[rt<<1][h],minv[rt<<1|1][h]); } void build(int l,int r,int rt) { sum[rt][0]=sum[rt][1]=0; maxv[rt][0]=maxv[rt][1]=-1; minv[rt][0]=minv[rt][1]=inf; if(l==r) return ; int m=(l+r)>>1; build(l,m,rt<<1); build(m+1,r,rt<<1|1); } int Query1(int l,int r,int rt,int v,int h) { if(maxv[rt][h]<v) return sum[rt][h]; if(minv[rt][h]>=v||l==r) return 0; int m=(l+r)>>1; int ls=rt<<1,rs=rt<<1|1; if(maxv[ls][h]<v) return sum[ls][h]+Query1(m+1,r,rs,v,h); else return Query1(l,m,ls,v,h); } int Query2(int l,int r,int rt,int v,int h) { if(minv[rt][h]>v) return sum[rt][h]; if(maxv[rt][h]<=v||l==r) return 0; int m=(l+r)>>1; int ls=rt<<1,rs=rt<<1|1; if(minv[rs][h]>v) return sum[rs][h]+Query2(l,m,ls,v,h); else return Query2(m+1,r,rs,v,h); } void Update(int p,int l,int r,int rt,int v,int h) { if(l==r) { if(v<0) { maxv[rt][h]=-1;minv[rt][h]=inf; sum[rt][h]=0; } else { maxv[rt][h]=minv[rt][h]=v; sum[rt][h]=1; } return; } int m=(l+r)>>1; if(p<=m) Update(p,l,m,rt<<1,v,h); else Update(p,m+1,r,rt<<1|1,v,h); PushUp(rt,h); } void dfs(int u) { int lbg,lsm,rbg,rsm; int sz=querys[u].size(); Node tmp; for(int i=0;i<sz;++i) { tmp=querys[u][i]; lsm=Query1(1,n,1,tmp.w,0); rsm=Query1(1,n,1,tmp.w,1); lbg=Query2(1,n,1,tmp.w,0); rbg=Query2(1,n,1,tmp.w,1); if(cnt-lsm-rsm-lbg-rbg>0) ans1[tmp.u]=-1; else { ans1[tmp.u]=rsm; ans2[tmp.u]=lbg+rbg+(lsm+rsm)*3; } } if(lson[u]<0) return ; cnt++; Update(rnk[u],1,n,1,ww[u],0); dfs(lson[u]); Update(rnk[u],1,n,1,-1,0); Update(rnk[u],1,n,1,ww[u],1); dfs(rson[u]); Update(rnk[u],1,n,1,-1,1); cnt--; } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int t; scanf("%d",&t); while(t--) { Init(); scanf("%d",&n); for(int i=1;i<=n;++i) { scanf("%d",&ww[i]); node[i].w=ww[i]; node[i].u=i; } sort(node+1,node+n+1); for(int i=1;i<=n;++i) rnk[node[i].u]=i; scanf("%d",&m); int u,a,b; for(int i=0;i<m;++i) { scanf("%d%d%d",&u,&a,&b); flag[a]=flag[b]=true; lson[u]=a;rson[u]=b; } for(int i=1;i<=n;++i) if(!flag[i]) {u=i;break;} scanf("%d",&q); Node tmp; for(int i=0;i<q;++i) { scanf("%d%d",&a,&b); tmp.u=i;tmp.w=b; querys[a].push_back(tmp); } build(1,n,1); lf=rn=cnt=0; dfs(u); for(int i=0;i<q;++i) { if(ans1[i]==-1) printf("0\n"); else printf("%d %d\n",ans1[i],ans2[i]); } } return 0; }