hdu4605 Magic Ball Game(树状数组)

题目链接:点这里!!!!


题意:

给定一棵N(N<=1e5)节点的树,每个节点要么有两个儿子(左右两个儿子),要么没有儿子,每个节点有一个权值w[i]。

一个权值为X球从根节点开始下落,每落到一个节点的时候,

1.如果X=W[i],或者没有儿子节点了,球停止下落。

2.如果X<W[i],球各有1/2的概率落到左右儿子节点。

3.如果X>W[i],球有1/8的概率落到左儿子,有7/8的概率落到右儿子。

给你q(q<=1e5)个询问,询问中包含v,x。问你权值为x的球从根节点(根节点是1)落到v节点的概率是多少。(落不到输出0,否则概率用7^x/2^y表示,即输出x和y就可以。)


题解:

1、这道题我们可以对所有询问离线,相当于求当前节点到根节点的路径上有多少数大于它,有多少数小于它,有多少数等于它,我们可以直接用树状树状实现。


2、从根节点开始dfs,到达x节点时,取出其中的询问,树状数组里存的是根节点到father[x]中的权值,我可以快速求出其中大于、等于、小于它的数有多少。


3、这道题就OK了,具体看代码实现。


代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<sstream>
#include<algorithm>
#include<vector>
#include<bitset>
#include<set>
#include<queue>
#include<stack>
#include<map>
#include<cstdlib>
#include<cmath>
#define PI 2*asin(1.0)
#define LL long long
#define pb push_back
#define pa pair<int,int>
#define clr(a,b) memset(a,b,sizeof(a))
#define lson lr<<1,l,mid
#define rson lr<<1|1,mid+1,r
#define bug(x) printf("%d++++++++++++++++++++%d\n",x,x)
#define key_value ch[ch[root][1]][0]C:\Program Files\Git\bin
const int  MOD = 1E9+7;
const LL N = 2e5+15;
const int maxn = 5e5+15;
const int letter = 130;
const int INF = 1e17;
const double pi=acos(-1.0);
const double eps=1e-10;
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int w[N],n,m,q,ps[N],cnt;
int c[2][N],ans[N][2];
vector<int>G[N];
vector<pa>que[N];
void init(){
    cnt=0;
    clr(c,0),clr(ans,0);
    for(int i=0;i<N;i++) G[i].clear(),que[i].clear();
}
int lowbit(int x) {return x&(-x);}
void update(int i,int val,int f){
    for(int x=i;x<=cnt;x+=lowbit(x)) c[f][x]+=val;
}
int getsum(int i,int f){
    int ans=0;
    for(int x=i;x>0;x-=lowbit(x)) ans+=c[f][x];
    return ans;
}
void dfs(int x){
    for(int i=0;i<que[x].size();i++){
        int id=que[x][i].first,pos=que[x][i].second;
        pos=lower_bound(ps+1,ps+cnt+1,pos)-ps;
        ///0 zuo   1you
        int lqb=getsum(cnt,0);
        int rqb=getsum(cnt,1);
        int lx=getsum(pos-1,0);  ///xiaoyu
        int rx=getsum(pos-1,1);
        int ld=lqb-getsum(pos,0);
        int rd=rqb-getsum(pos,1);
        if(lx+ld+rx+rd!=lqb+rqb){
            ans[id][0]=-1;
            continue;
        }
        ans[id][0]=rx;
        ans[id][1]=lx*3+rx*3+ld+rd;
    }
    for(int i=0;i<G[x].size();i++){
        int vs=lower_bound(ps+1,ps+cnt+1,w[x])-ps;
        update(vs,1,i);
        dfs(G[x][i]);
        update(vs,-1,i);
    }
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        init();
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",w+i),ps[++cnt]=w[i];
        scanf("%d",&m);
        for(int i=0;i<m;i++){
            int u,a,b;
            scanf("%d%d%d",&u,&a,&b);
            G[u].pb(a),G[u].pb(b);
        }
        scanf("%d",&q);
        for(int i=1;i<=q;i++){
            int id,x;
            scanf("%d%d",&id,&x);
            que[id].pb(make_pair(i,x));
            ps[++cnt]=x;
        }
        sort(ps+1,ps+cnt+1);
        cnt=unique(ps+1,ps+cnt+1)-(ps+1);
        dfs(1);
        for(int i=1;i<=q;i++){
            if(ans[i][0]==-1) puts("0");
            else printf("%d %d\n",ans[i][0],ans[i][1]);
        }
    }
    return 0;
}
/*
*/


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值