HDU6059(两棵字典树)

Kanade's trio

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 767    Accepted Submission(s): 278


Problem Description
Give you an array  A[1..n] ,you need to calculate how many tuples  (i,j,k)  satisfy that  (i<j<k)  and  ((A[i] xor A[j])<(A[j] xor A[k]))

There are T test cases.

1T20

1n5105

0A[i]<230
 

Input
There is only one integer T on first line.

For each test case , the first line consists of one integer  n  ,and the second line consists of  n  integers which means the array  A[1..n]
 

Output
For each test case , output an integer , which means the answer.
 

Sample Input
  
  
1 5 1 2 3 4 5
 

Sample Output
  
  
6
题意:让你在所给的序列找出有多少三元组i,j,k满足a[i]xor a[j] < a[j] xor a[k]
解题思路:
用两棵字典树维护,枚举a[j],j前面序列a[i]用一棵字典树维护,j后面的a[k]用一棵字典树维护,然后对于每个a[j],从他的最高位开始,在两棵树中分别找出这一位不同的位对应的数量,比如当前位是0,则需要在前缀树中找出这一位为0的个数x1, 在后缀树中找出这一位为1的个数x2,所以当前满足a[i] xor a[j] < a[j] xor a[k]的三元组数量是x1 * x2,然后接着往下找下去就行。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5e5 + 10;
int n;
int a[maxn];
ll ans[40][2];//表示每一层的结果
struct node{
    int Next[2];
    ll sum;//个数
    node(){
        memset(Next, -1, sizeof(Next));
        sum = 0;
    }
};
node Tree1[maxn<<2], Tree2[maxn<<2];
int res1, res2;
int root1, root2;
void cal(int root, int status, int d, int type, int op)
{
    node *Treex, *Treey;
    if(type == 0)
    {
        Treex = Tree1;
        Treey = Tree2;
    }
    else
    {
        Treex = Tree2;
        Treey = Tree1;
    }
    if(type == 0)//前缀树
    {
        if(status == 0)
        {
            int x1 = Treex[root].Next[0];
            int x2 = Treey[root].Next[1];
            if(x1 != -1 && x2 != -1)
            {
                ll sum1 = Treex[x1].sum;
                ll sum2 = Treey[x2].sum;
                ans[d][0] -= sum1 * sum2;
                ans[d][0] += (sum1 + op * 1) * (sum2);
            }
        }
        else
        {
            int x1 = Treex[root].Next[1];
            int x2 = Treey[root].Next[0];
            if(x1 != -1 && x2 != -1)
            {
                ll sum1 = Treex[x1].sum;
                ll sum2 = Treey[x2].sum;
                ans[d][1] -= sum1 * sum2;
                ans[d][1] += (sum1 + op * 1) * (sum2);
            }
        }
    }
    else
    {
        if(status == 0)
        {
            int x1 = Treex[root].Next[0];
            int x2 = Treey[root].Next[1];
            if(x1 != -1 && x2 != -1)
            {
                ll sum1 = Treex[x1].sum;
                ll sum2 = Treey[x2].sum;
                ans[d][1] -= sum1 * sum2;
                ans[d][1] += (sum1 + op * 1) * (sum2);
            }
        }
        else
        {
            int x1 = Treex[root].Next[1];
            int x2 = Treey[root].Next[0];
            if(x1 != -1 && x2 != -1)
            {
                ll sum1 = Treex[x1].sum;
                ll sum2 = Treey[x2].sum;
                ans[d][0] -= sum1 * sum2;
                ans[d][0] += (sum1 + op * 1) * (sum2);
            }
        }
    }
}
void Insert(int x, int type, node Tree[], int before)
{
    int root;
    if(type == 0)//前缀树
    {
        root = root1;
    }
    else root = root2;
    for(int i = 30; i >= 0; i--)
    {
        int num = (x>>i)&1;
        if(Tree[root].Next[num] == -1)
        {
            int res;
            if(type == 0) res = ++res1;
            else res = ++res2;
            Tree[root].Next[num] = res;
        }
        if(before) cal(root, num, i, type, 1);
        int id = Tree[root].Next[num];
        Tree[id].sum++;
        root = id;
    }
}
void Delete(int x, int type, node Tree[], int before)
{
    int root;
    if(type == 0)//前缀树
    {
        root = root1;
    }
    else root = root2;
    for(int i = 30; i >= 0; i--)
    {
        int num = (x>>i)&1;
        if(before) cal(root, num, i, type, -1);
        int id = Tree[root].Next[num];
        Tree[id].sum--;
        root = id;
    }
}
void init()
{
    res1 = res2 = 0;
    memset(ans, 0, sizeof(ans));
    int Maxn = (maxn<<2);
    for(int i = 0; i < Maxn; i++)
    {
        Tree1[i].Next[0] = Tree1[i].Next[1] = -1;
        Tree2[i].Next[0] = Tree2[i].Next[1] = -1;
        Tree1[i].sum = 0;
        Tree2[i].sum = 0;
    }
}
void initAns(int r1, int r2, int d)
{
    if(d < 0 || r1 == -1 || r2 == -1) return;
    int x1 = Tree1[r1].Next[0];
    int x2 = Tree2[r2].Next[1];
    if(x1 != -1 && x2 != -1)
    {
        ans[d][0] += Tree1[x1].sum * Tree2[x2].sum;
    }
    initAns(x1, x1, d - 1);
    x1 = Tree1[r1].Next[1];
    x2 = Tree2[r2].Next[0];
    if(x1 != -1 && x2 != -1)
    {
        ans[d][1] += Tree1[x1].sum * Tree2[x2].sum;

    }
    initAns(x1, x1, d - 1);
}
ll solve(int x)
{
    ll sum = 0;
    for(int i = 30; i >= 0; i--)
    {
        int num = (x>>i)&1;
        sum += ans[i][num];
    }
    return sum;
}
int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &n);
        init();
        root1 = ++res1;
        root2 = ++res2;
        for(int i = 1; i <= n; i++)
        {
            scanf("%d", &a[i]);
            Insert(a[i], 0, Tree1, 0);
            Insert(a[i], 1, Tree2, 0);
        }
        initAns(root1, root2, 30);
        Delete(a[1], 1, Tree2, 1);
        for(int i = 2; i <= n; i++)
        {
            Delete(a[i], 0, Tree1, 1);
        }
        ll ssum = 0;
        for(int i = 2; i < n; i++)
        {
            Delete(a[i], 1, Tree2, 1);
            ssum += solve(a[i]);
            Insert(a[i], 0, Tree1, 1);
        }
        printf("%lld\n", ssum);
    }
    return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值