Magic Ball Game - HDU 4605 树状数组

时间:2022-01-19 21:56:21

Magic Ball Game

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1774    Accepted Submission(s): 497


Problem Description
When the magic ball game turns up, Kimi immediately falls in it. The interesting game is made up of N balls, each with a weight of w[i]. These N balls form a rooted tree, with the 1st ball as the root. Any ball in the game has either 0 or 2 children ball. If a node has 2 children balls, we may define one as the left child and the other as the right child.
The rules are simple: when Kimi decides to drop a magic ball with a weight of X, the ball goes down through the tree from the root. When the magic ball arrives at a node in the tree, there's a possibility to be catched and stop rolling, or continue to roll down left or right. The game ends when the ball stops, and the final score of the game depends on the node at which it stops.
After a long-time playing, Kimi now find out the key of the game. When the magic ball arrives at node u weighting w[u], it follows the laws below:
1  If X=w[u] or node u has no children balls, the magic ball stops.
2  If X<w[u], there's a possibility of 1/2 for the magic ball to roll down either left or right.
3  If X>w[u], the magic ball will roll down to its left child in a possibility of 1/8, while the possibility of rolling down right is 7/8.
In order to choose the right magic ball and achieve the goal, Kimi wonders what's the possibility for a magic ball with a weight of X to go past node v. No matter how the magic ball rolls down, it counts if node v exists on the path that the magic ball goes along.
Manual calculating is fun, but programmers have their ways to reach the answer. Now given the tree in the game and all Kimi's queries, you're required to answer the possibility he wonders.
 

Input
The input contains several test cases. An integer T(T≤15) will exist in the first line of input, indicating the number of test cases.
Each test case begins with an integer N(1≤N≤10 5), indicating the number of nodes in the tree. The following line contains N integers w[i], indicating the weight of each node in the tree. (1 ≤ i ≤ N, 1 ≤ w[i] ≤ 10 9, N is odd)
The following line contains the number of relationships M. The next M lines, each with three integers u,a and b(1≤u,a,b≤N), denotes that node a and b are respectively the left child and right child of node u. You may assume the tree contains exactly N nodes and (N-1) edges.
The next line gives the number of queries Q(1≤Q≤10 5). The following Q lines, each with two integers v and X(1≤v≤N,1≤X≤10 9), describe all the queries.
 

Output
If the magic ball is impossible to arrive at node v, output a single 0. Otherwise, you may easily find that the answer will be in the format of 7 x/2 y . You're only required to output the x and y for each query, separated by a blank. Each answer should be put down in one line.
 

Sample Input
 
 
1 3 2 3 1 1 1 2 3 3 3 2 1 1 3 4
 

Sample Output
 
 
0 0 0 1 3
 

题意:有T组测试数据,N表示这棵树有N个点,下一行的N个数,表示每个点的权值W,M表示边的关系,接下来的M行,每行有三个数字,u,b,b,表示点a和点b分别是点u的左儿子和右儿子。Q表示查询数,接下来的Q行,每行两个数字,v和X。

思路:首先离散化,在dfs的时候更新树状数组,需要两个树状数组,分别表示从根节点到这个店是往左走的还是往右走的。

AC代码如下:

#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<cstring>
#include<map>
#include<vector>
#include<algorithm>
using namespace std;
map<int,int> MAT;
int match[2][200010],mat[200010],op[200010];
int maxn,T,t,w[100010],f[100010],son[100010][2],vis[100010],leaf[100010],root=1,ans[100010][2];
struct node
{
    int w,pos;
};
vector<node> vc[100010];
node a;
int lowbit(int x)
{
    return x&(-x);
}
void update(int i,int f,int val)
{
    for(;i<=maxn;i+=lowbit(i))
       match[f][i]+=val;
}
int query(int i,int f)
{
    int ret=0;
    for(;i>0;i-=lowbit(i))
       ret+=match[f][i];
    return ret;
}
void dfs(int u,int num)
{
    int i,k,l1,l2,W;
    k=vc[u].size();
    for(i=0;i<k;i++)
    {
        W=MAT[vc[u][i].w];
        if(mat[W]>0)
          ans[vc[u][i].pos][0]=-1;
        else
        {
            l1=query(W,0);
            l2=query(W,1);
            ans[vc[u][i].pos][0]=l2;
            ans[vc[u][i].pos][1]=num+(l1+l2)*2;
        }
    }
    if(leaf[u]!=t)
      return;
    W=MAT[w[u]];
    mat[W]++;
    update(W,0,1);
    dfs(son[u][0],num+1);
    update(W,0,-1);
    update(W,1,1);
    dfs(son[u][1],num+1);
    update(W,1,-1);
    mat[W]--;
}
int main()
{
    int n,m,u,l,r,i,j,k;
    scanf("%d",&T);
    for(t=1;t<=T;t++)
    {
        maxn=0;
        MAT.clear();
        scanf("%d",&n);
        op[0]=0;
        for(i=1;i<=n;i++)
        {
            scanf("%d",&w[i]);
            if(MAT[w[i]]!=1)
            {
                MAT[w[i]]=1;
                op[0]++;
                op[op[0]]=w[i];
            }
            vc[i].clear();
        }
        scanf("%d",&m);
        for(i=1;i<=m;i++)
        {
            scanf("%d%d%d",&u,&l,&r);
            leaf[u]=t;
            son[u][0]=l;
            son[u][1]=r;
            vis[l]=t;
            vis[r]=t;
        }
        scanf("%d",&m);
        for(i=1;i<=m;i++)
        {
            scanf("%d%d",&u,&k);
            a.w=k;
            a.pos=i;
            if(MAT[k]!=1)
            {
                MAT[k]=1;
                op[0]++;
                op[op[0]]=k;
            }
            vc[u].push_back(a);
        }
        for(i=1;i<=n;i++)
           if(vis[i]!=t)
           {
               root=i;
               break;
           }
        MAT.clear();
        sort(op+1,op+1+op[0]);
        for(i=1;i<=op[0];i++)
           MAT[op[i]]=i;
        maxn=op[0];
        dfs(root,0);
        for(i=1;i<=m;i++)
           if(ans[i][0]==-1)
             printf("0\n");
           else
             printf("%d %d\n",ans[i][0],ans[i][1]);
    }
}