HDU6059(两棵字典树)

来源:互联网 发布:淘宝国产高仿手办 编辑:程序博客网 时间:2024/06/13 18:52

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
151 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;}