zoukankan      html  css  js  c++  java
  • 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
    ");
                    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
    ",B,C+D+3*(A+B));
            } 
        }
    }
  • 相关阅读:
    java核心技术卷上学习笔记
    个人作业——软件工程实践总结作业
    个人作业——软件产品案例分析
    软件工程作业-结对编程 2.0
    软件工程作业-结对编程 1.0
    软件工程作业2.0
    软件工程作业1.0
    《面向对象程序设计》c++第六次作业___calculator SE
    面向对象程序设计作业 6.1~6.4
    面向对象程序设计作业 5.1~5.5
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/14015416.html
Copyright © 2011-2022 走看看