hdu 4605 Magic Ball Game 多校第一场

对于某个询问(u, x),首先判断从根到 u的路径上是否有点权等于x。若存在,则到达当前点
的概率是0。
不妨定义往左走的路径为“左路径”,往右走的路径称为“右路径”。设左路径上大于 x的点权
有a1个,小于 x的点权有a2个,则通过所有左路径并到达节点 u的概率是p1 = (1/2)^a1 *(1/8)^a2
类似地,设右路径上大于x的点权有b1个,小于x的点权有b2个,则通过所有右路径并到达
点u的概率p2 = (1/2)^b1 * (7/8)^b2
。最后的答案就是p = p1*p2.
求根到u的路径上大于(小于/等于)x的点权数量,可以在离线之后对树做一次 dfs,并用
树状数组维护当前路径中的所有点权。总复杂度是O(QlogN).

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
#include <iostream>
#include <map>
using namespace std;
const int MAXN = 100100;
int c[2*MAXN][2];
int tree[MAXN][2];
map<int,int>mp;
vector<int>vv[MAXN];
int num[2*MAXN];
int w[MAXN];
bool vis[MAXN],judge[MAXN];
int tot;
struct query
{
    int x,u;
    int a,b;
}q[MAXN];
int lowbit(int x)
{
    return x&(-x);
}
void updata(int x,int p,int d)
{
    for(;x<=tot;x+=lowbit(x)) c[x][p]+=d;
}
int sum(int x,int p)
{
    int res=0;
    for(;x>0;x-=lowbit(x)) res+=c[x][p];
    return res;
}
void dfs(int u)
{
    int siz=vv[u].size();
    for(int i=0;i<siz;i++)
    {
        int it=vv[u][i];
        int t=mp[q[it].x];
        if(sum(t,0)-sum(t-1,0)||sum(t,1)-sum(t-1,1))
        {
            q[it].a=-1;
            q[it].b=-1;
            continue;
        }
       /* if(vis[t])
        {
            judge[it]=1;
            continue;
        }*/
        q[it].a=sum(t-1,1);
        q[it].b=sum(t-1,0)*3+(sum(tot,0)-sum(t,0))+sum(t-1,1)*3+(sum(tot,1)-sum(t,1));

    }
    if(tree[u][0])
    {
        int t=mp[w[u]];
        vis[t]=1;
        updata(t,0,1);
        dfs(tree[u][0]);
        updata(t,0,-1);
        updata(t,1,1);
        dfs(tree[u][1]);
        updata(t,1,-1);
        vis[t]=0;
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        mp.clear();
        memset(c,0,sizeof(c));
        memset(tree,0,sizeof(tree));
        memset(vis,0,sizeof(vis));
        memset(judge,0,sizeof(judge));
        int n,m,Q;
        scanf("%d",&n);
        for(int i=0;i<=n;i++) vv[i].clear();
        int cnt=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&w[i]);
            num[cnt++]=w[i];
        }
        scanf("%d",&m);
        while(m--)
        {
            int u,a,b;
            scanf("%d%d%d",&u,&a,&b);
            tree[u][0]=a;
            tree[u][1]=b;
            vis[a]=1;
            vis[b]=1;
        }

        scanf("%d",&Q);
        tot=0;
        for(int i=1;i<=Q;i++)
        {
            //int v,x;
            scanf("%d%d",&q[i].u,&q[i].x);
            vv[q[i].u].push_back(i);
            num[cnt++]=q[i].x;
        }
        sort(num,num+cnt);
        for(int i=0;i<cnt;i++)
        {
            if(mp[num[i]]) continue;
            mp[num[i]]=++tot;
        }
        int u;
        for(int i=1;i<=n;i++) if(!vis[i])
        {
            u=i;
            break;
        }
        memset(vis,0,sizeof(vis));
        dfs(u);
        for(int i=1;i<=Q;i++)
        {
            if(q[i].a==-1&&q[i].b==-1) puts("0");
            else
            {
                printf("%d %d\n",q[i].a,q[i].b);
            }
        }
    }
}


 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值