[HDU]6059 Kanade's trio

URL : http://acm.hdu.edu.cn/showproblem.php?pid=6059

题意

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]))

题解

看了别人题解大半天,才终于明白,随便记下自己的理解

对于所有的 ((A[i] xor A[j])<(A[j] xor A[k]))
假设我们用字典树记录了A[1 ~ k-1],当前加入 Ak
字典树中以第30位为根,假设当前处理到了第 p 位
Ak[p] 代表 Ak 第 p 位的值,且 AiAk 高位都是相同的
Ak[p]=1 时:
必然 Ai[p]=0Aj[p]=0 时才有价值,下面考虑 Aj 的取值情况
1. Aj 的高位与 AkAk 都相同的情况 1LL * dat[Fson].num * (dat[Fson].num - 1) / 2;
2. Aj 的高位与 AkAk 不都都相同的情况 dat[Fson].num * (cnt[o][1-t] - dat[Fson].num) - dat[Fson].exn;

Ak[p]=0 时:同上讨论即可

注: 减去 dat[Fson].exn,dat[Fson].exn是 i > j 时 满足条件2 的情况

#include
#include

typedef long long LL;
const int MAXN = 2e5 + 5;
struct node {int num, exn, son[2]; } dat[31 * MAXN];
LL ans = 0;
int sz, cnt[31][2];

inline void cle(int x) {
    dat[x].son[0] = dat[x].son[1] = dat[x].num = dat[x].exn = 0;
}

inline void add(int n, int o) {
    int z = 0;
    while(o >= 0) {
        int t = n>>o&1;
        int &Fson = dat[z].son[1-t];
        int &Tson = dat[z].son[  t];
        if(Fson) {
            ans += 1LL * dat[Fson].num * (dat[Fson].num - 1) / 2;
            ans += 1LL * dat[Fson].num * (cnt[o][1-t] - dat[Fson].num) - dat[Fson].exn;
        }
        if(Tson) {
            z = Tson;
        }
        else {
            z = Tson = ++sz;
            cle(Tson);
        }
        ++dat[z].num;
        ++cnt[o][t];
        dat[z].exn += cnt[o][t] - dat[z].num; // all of j < i in this node
        --o;
    }
}

int main()
{
    int T, n, x;
    scanf("%d", &T);
    while(T--) {
        memset(cnt, 0, sizeof(cnt));
        scanf("%d", &n);
        ans = sz = 0;
        cle(0);
        while(n--) {
            scanf("%d", &x);
            add(x, 30);
        }
        printf("%lld\n", ans);
    }
    return 0;
}

你可能感兴趣的:(字典树)