HDU 6059 Kanade's trio

题意:
给一个序列a1,a2,a3…………..an
让你寻找(i,j,k)对,满足ai oxr aj < aj oxr ak
主要是要想到用字母树去做。
我们将每个数插入到字母树中,然后每次查入的时候计算以当前插入的数为k的满足条件的(i,j,k)对有多少个。
但是题目要求了i < j < k
那么我们可以这样计算,将每个数拆成二进制位,我们匹配到了第w位,我们计算第w位的贡献,假设w=1,那么我们可以加上之前的前w-1位都匹配上了的w=0的数量乘以第w位为0的数量,这样就表明从第w位开始ak与前面的分离。这样的话,我们就计算多了一些,我们这样就计算了所有的i,j,k对满足ai oxr aj < aj oxr ak,但是i不一定在j前面。
现在的问题就变成了我们如何统计i不在j之前的满足ai oxr aj < aj oxr ak的对数。那么我们可以在进行匹配的时候顺便把这个维护了。
感觉我没有太讲清楚,具体的看代码吧。
就是那个sum维护那个不满足条件的。

#include <bits/stdc++.h>

typedef long long ll;
using namespace std;
const int maxn = 5e5+7;
template <typename T>inline void read(T &_x_){
    _x_=0;bool f=false;char ch=getchar();
    while (ch<'0'||ch>'9') {if (ch=='-') f=!f;ch=getchar();}
    while ('0'<=ch&&ch<='9') {_x_=_x_*10+ch-'0';ch=getchar();}
    if(f) _x_=-_x_;
}

struct node{
    node*ch[2];
    ll v,de;
    node(){
        v = 0,de=0;
        ch[0] = ch[1] = NULL;
    }
};
node*root,*rt;
ll val[maxn],sum[maxn][2];
ll ans=0;

void insert(int n){
    rt=root;
    for(int level=30;level>=0;level--){
        int id=(n>>level)&1;
        sum[level][id]++;
        if(rt->ch[id]==NULL) rt->ch[id]=new node();
        if(rt->ch[1-id]!=NULL){
            ans+=(sum[level][1-id])*(rt->ch[1-id]->v);
            ans-=rt->ch[1-id]->de;
        }
        rt=rt->ch[id];
        rt->v++;
        rt->de+=sum[level][id];
    }
}

int main(){
    ll t,n;
    read(t);
    while(t--){
        ans=0;
        memset(sum,0,sizeof(sum));
        root=new node();
        read(n);
        for(int i=1;i<=n;i++){
            read(val[i]);
            insert(val[i]);
        }
        printf("%I64d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值