求数组中i<j<k 并且ai^aj<aj^ak的三元组组数
枚举插入ak,让ak中每一位作为最高位,查找字典树内最高位不同的数字数量
注意把ak的每个前缀做一个bad标记
存储让这个前缀作为i可以与字典树内形成i,j对的个数,这些不满足i<j
ai : 1 1 0 1
aj : ? 0 0 0
ak : 1 0 0 1
结合这个图会直观点。。
#include<bits/stdc++.h>
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<iostream>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<iomanip>
using namespace std;
#define ll long long
#define pb push_back
#define FOR(a) for(int i=1;i<=a;i++)
const int inf=0x3f3f3f3f;
const int maxn=5e5+9;
struct NODE{
int cnt;
int nxt[2];
int bad;
}trie[maxn*30];
int sz;
int dig[30];
int cnt[30][2];
ll ans;
int arr[maxn];
void cal(int p,int cnt){
ans+=1ll*trie[p].cnt*(trie[p].cnt-1)>>1; //ai,aj都在前缀内选
ans+=1ll*trie[p].cnt*(cnt-trie[p].cnt)-trie[p].bad; //ai在前缀,aj不在
}
void insert(){
int now=0;
for(int i=0;i<30;i++){
if(!trie[now].nxt[dig[i]]){
trie[now].nxt[dig[i]]=++sz;
}
if(trie[now].nxt[1-dig[i]]){
cal(trie[now].nxt[1-dig[i]],cnt[i][1-dig[i]]);
}
now=trie[now].nxt[dig[i]];
trie[now].cnt++;
trie[now].bad+=cnt[i][dig[i]]-trie[now].cnt;
}
}
int main(){
int T;
scanf("%d",&T);
while(T--){
memset(trie,0,sizeof trie);memset(cnt,0,sizeof cnt);
int n;scanf("%d",&n);
sz=0,ans=0;
FOR(n){
scanf("%d",&arr[i]);
for(int j=29;j>=0;j--){
dig[j]=arr[i]%2;cnt[j][arr[i]%2]++;arr[i]/=2;
}
insert();
}
printf("%lld\n",ans);
}
}
学了字典树基本没用过。。
接着补题之前做做异或题吧。。