HDU 6059 Kanade's trio

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

题意:给你一个数列,找出i<j<k且a[i]^a[j]<a[j]^a[k]的三元组个数;

思路:字典树;

可以知道,如满足以上关系,就是要找出a[i]和a[k]第一位不同的位,另a[j]的这一位与a[I]相同即可,那么就分为两种情况:

(1)a[i],a[j],a[k]的前t-1位都相同,那么对答案的贡献就是d[Fson].num*(d[Fson].num-1)/2;

  这里Fson是当前位的兄弟节点,a[i],a[j]都在这个子树中,显然,必然有一大一小两个a[i],a[j]来满足;

(2)a[i],a[k]的前t-1位都相同,a[j]不同,这里a[j]的前t-1为其实是什么不重要,所以加上第一种情况刚好是全部解,对答案的贡献为:

  d[Fson].num*(cnt[k][1-t]-d[Fson].num)-d[Fson].ng

  后面减去的是不合法的,实际上就是i,j的选取问题,d[Fson].num是我想要的i,cnt[k][1-t]-d[Fson].num是我要的j,但是问题是i,j是有先后顺序的

  我不能保证我要的j一定都在i的后面出现,但是,我们可以知道当插入一个节点时,如果要把这个节点作为i,前面出现过的节点肯定不能作为j,那么

  对于每一个新的i节点,有多少不合法的呢,是cnt[k][t]-d[z].num;这也很好理解,因为我们知道(2)中i和j不会再同一子树中,那么cnt[k][t]-d[z].num就是

  当前位相同的总数减去当前子树的数量,得到的就是,非同一子树中同位相同的比当前节点早插入的节点,即上面说的非法节点;

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
const int MAXN=2e5+5;
struct Node
{
    int num,ng,son[2];
}d[31*MAXN];
LL ans=0;
int sz,cnt[31][2];

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

void add(int n,int k)
{
    int z=0; //插入时当前节点
    while(k>=0)
    {
        int t=n>>k&1;//插入数当前位
        int &Fson = d[z].son[1-t]; //这里用引用是因为要更新原始数据
        int &Tson = d[z].son[t];
        if(Fson)//如果我的兄弟节点存在,操作
        {
            ans+=1LL*d[Fson].num*(d[Fson].num-1)/2;//i,j,k前t-1位都相同
            ans+=1LL*d[Fson].num*(cnt[k][1-t]-d[Fson].num)-d[Fson].ng;//i,k前t-1位相同,j不一定相同,之所以减掉不成立的,是因为i,j是要有一个顺序
        }
        if(Tson)//如果下一位的节点存在,直接顺延下去
        {
            z=Tson;
        }
        else//如果下一位的节点,不存在,创建个新节点,并初始化
        {
            z=Tson=++sz;
            cle(z);
        }
        d[z].num++;
        cnt[k][t]++;
        d[z].ng+=cnt[k][t]-d[z].num;
        k--;
    }
}

int main()
{
    //freopen("input.txt","r",stdin);
    int T,n,x;
    for(scanf("%d",&T);T;T--)
    {
        memset(cnt,0,sizeof cnt);
        scanf("%d",&n);
        ans=0,sz=0;
        cle(0);
        while(n--)
        {
            scanf("%d",&x);
            add(x,30);
        }
        printf("%lld
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/MeowMeowMeow/p/7285199.html