Kanade's trio 2017多校#3 trie

求数组中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
",ans);
	}
}
学了字典树基本没用过。。

接着补题之前做做异或题吧。。

原文地址:https://www.cnblogs.com/Drenight/p/8611291.html