HDU4605 Magic Ball Game(可持久化线段树)

当魔术球比赛出现时,基米立即掉入其中。有趣的游戏由N个球组成,每个球的权重均为w [i]。这N个球以第一个球为根形成一棵有根的树。游戏中的任何球都有0或2个子球。如果一个节点有2个子球,我们可以定义一个为左子球,另一个为右子球。
规则很简单:当Kimi决定放下重量为X的魔术球时,该球将从树根向下穿过树。当魔术球到达树上的某个节点时,就有可能被抓住并停止滚动,或者继续向左或向右滚动。当球停止时游戏结束,并且游戏的最终得分取决于停止的节点。
经过长时间的游戏,Kimi现在可以找到游戏的关键。当魔术球到达节点u的权重w [u]时,它遵循以下定律:
1如果X = w [u]或节点u没有子球,则魔球停止。
2如果X <w [u],则魔术球向左或向右滚动的可能性为1/2。
3如果X> w [u],则魔球将以1/8的可能性向下滚动到其左子对象,而右滚的可能性为7/8。
为了选择正确的魔术球并实现目标,Kimi想知道重量为X的魔术球越过节点v的可能性。无论魔术球如何滚动,它都会计算节点v是否存在于节点上。魔术球走的路径。
手动计算很有趣,但是程序员有自己的方法来找到答案。现在考虑到游戏中的树和所有Kimi的查询,您需要回答他想知道的可能性。
输入值
输入包含几个测试用例。输入的第一行中将存在整数T(T≤15),指示测试用例的数量。
每个测试用例均以整数N(1≤N≤105)开头,表示树中的节点数。下一行包含N个整数w [i],表示树中每个节点的权重。 (1≤i≤N,1≤w [i]≤109,N为奇数)
下一行包含关系M的数量。接下来的M行分别具有三个整数u,a和b(1≤u,a,b≤N),表示节点a和b分别是左子节点和右子节点节点u的。您可以假设树正好包含N个节点和(N-1)个边。
下一行给出查询数量Q(1≤Q≤105)。以下Q行(每个行都有两个整数v和X(1≤v≤N,1≤X≤109))描述了所有查询。
输出量
如果魔术球不可能到达节点v,则输出单个0。否则,您可能会很容易发现答案将采用7x / 2y的格式。您只需要为每个查询输出x和y,用空格分隔。每个答案都应该放在一行中。

Solution

建立两颗主席树分别统计从根节点到当前节点的路径中,下一步是左孩子的节点情况和下一步是右孩子的节点情况,好题

//如果x=w[u],则魔球停止
//如果x>w[u],则魔球1/8向左,7/8向右
//如果x<w[u],则向左向右的可能性均为1/2
//节点v和根节点的路径上,如果有一个w[u]==x,则输出0
//否则分别计算
//小于x的节点中,如果路径的下一步是左孩子,则y+=3
//如果路径的下一步是右孩子,则x+=1,y+=3
//大于x的节点总数加起来是tt,y+=tt

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+100;
const int M=maxn*40;
int n,m,q;
int t[maxn],a[maxn];
int tot;
int T[maxn];
int lson[M],rson[M],c[M][2];
//c[i][0]表示起点到i的路径中,下一步是左孩子的情况
//c[i][1]表示起点到i的路径中,下一步是右孩子的情况
int build (int l,int r) {
    int root=tot++;
    c[root][0]=c[root][1]=0;
    if (l!=r) {
        int mid=(l+r)>>1;
        lson[root]=build(l,mid);
        rson[root]=build(mid+1,r);
    }
    return root;
}
int up (int root,int p,int v,int f) {
    int newRoot=tot++;
    int tmp=newRoot;
    int l=1,r=m;
    c[newRoot][f]=c[root][f]+v;
    c[newRoot][!f]=c[root][!f];
    while (l<r) {
        int mid=(l+r)>>1;
        if (p<=mid) {
            lson[newRoot]=tot++;
            rson[newRoot]=rson[root];
            newRoot=lson[newRoot];
            root=lson[root];
            r=mid;
        }
        else {
            rson[newRoot]=tot++;
            lson[newRoot]=lson[root];
            newRoot=rson[newRoot];
            root=rson[root];
            l=mid+1;
        }
        c[newRoot][f]=c[root][f]+v;
        c[newRoot][!f]=c[root][!f];
    }
    return tmp;
}

int query (int left_root,int right_root,int l,int r,int L,int R,int f) {
    if (L>R) return 0;
    if (l>=L&&r<=R) return c[right_root][f]-c[left_root][f];
    int mid=(l+r)>>1;
    int ans=0;
    if (L<=mid) ans+=query(lson[left_root],lson[right_root],l,mid,L,R,f);
    if (R>mid) ans+=query(rson[left_root],rson[right_root],mid+1,r,L,R,f);
    return ans;
}

vector<int> g[maxn];
void dfs (int u) {
    for (int i=0;i<g[u].size();i++) {
        T[g[u][i]]=up(T[u],a[u],1,i);
        dfs(g[u][i]);
    }
}

struct qnode {
    int x,y;
}Q[maxn];
int main () {
    int _;
    scanf("%d",&_);
    while (_--) {
        scanf("%d",&n);
        tot=0;
        int cnt=0;
        for (int i=1;i<=n;i++) scanf("%d",a+i),t[++cnt]=a[i],g[i].clear();
        int mm;
        scanf("%d",&mm);
        while (mm--) {
            int u,a,b;
            scanf("%d%d%d",&u,&a,&b);
            g[u].push_back(a);
            g[u].push_back(b);
        }
        scanf("%d",&q);
        for (int i=1;i<=q;i++) {
            scanf("%d%d",&Q[i].x,&Q[i].y);
            t[++cnt]=Q[i].y;
        }
        sort(t+1,t+cnt+1);
        m=unique(t+1,t+cnt+1)-t-1;
        for (int i=1;i<=n;i++) a[i]=upper_bound(t+1,t+m+1,a[i])-t-1;
        for (int i=1;i<=q;i++) Q[i].y=upper_bound(t+1,t+m+1,Q[i].y)-t-1;
        T[1]=build(1,m);
        dfs(1);
        for (int i=1;i<=q;i++) {
            if (query(T[1],T[Q[i].x],1,m,Q[i].y,Q[i].y,0)||query(T[1],T[Q[i].x],1,m,Q[i].y,Q[i].y,1)) {
                printf("0\n");
                continue;
            }
            
            int A=query(T[1],T[Q[i].x],1,m,1,Q[i].y-1,0);//向左走的比Q[i].y小的数
            int B=query(T[1],T[Q[i].x],1,m,1,Q[i].y-1,1);//向右走的比Q[i].y小的数
            int C=query(T[1],T[Q[i].x],1,m,Q[i].y+1,m,0);//向左走的比Q[i].y大的数
            int D=query(T[1],T[Q[i].x],1,m,Q[i].y+1,m,1);//向右走的比Q[i].y大的数         
            printf("%d %d\n",B,C+D+3*(A+B));
        } 
    }
}

 

posted @ 2020-11-21 13:41  zlc0405  阅读(91)  评论(0编辑  收藏  举报