#ifndef AFDS_BINARY_TRIE
#define AFDS_BINARY_TRIE
// TODO: Require to be rewritten.// Thanks neal for this template.#include<array>
#include<cstdint>
#include<vector>constintBITS=30;constintINF=1e9+7;structBinaryTrie{// 01-TriestaticconstintALPHABET=2;structNode{constintparent;intwords_here=0;// How many words EXACTLY here.intstarting_with=0;// How many words have the PREFIX of this node.intmin_index=INF;// The minimum index of words which have PREFIX of this node.intmax_index=-INF;// The maximum index of words which have PREFIX of this node.std::array<int,ALPHABET>child;Node(intp=-1):parent(p){child.fill(-1);}};staticconstintROOT=0;std::vector<Node>tr={Node()};BinaryTrie(inttotal_length=-1){// Sum of |s|, leave -1 if don't know.if(total_length>=0)tr.reserve(total_length+1);}// Returns the Node reference of word.// NOTICE: this function creates a new Node if word isn't in the trie.Node&operator[](uint64_tword){returntr[build(word,0)];}// Get or create c-th (c = 0, 1) child of node// Returns BinaryTrie node.intget_or_create_child(intnode,intc){if(tr[node].child[c]==-1){tr[node].child[c]=(int)tr.size();tr.push_back(Node(node));}returntr[node].child[c];}// Build rootpath of word, insert delta (个) words// Returns BinaryTrie node.intbuild(uint64_tword,intdelta){intnode=ROOT;for(inti=BITS-1;i>=0;i--){tr[node].starting_with+=delta;node=get_or_create_child(node,word>>i&1);}tr[node].starting_with+=delta;returnnode;}// Insert a word with the index of index, INF if index is unknown.// Returns BinaryTrie node.intinsert(uint64_tword,intindex=INF){intnode=build(word,1);tr[node].words_here+=1;for(intx=node;x!=-1;x=tr[x].parent){if(index!=INF){tr[x].min_index=std::min(tr[x].min_index,index);tr[x].max_index=std::max(tr[x].max_index,index);}}returnnode;}// Find such an x inserted in the trie that word ^ x is minimized.// Returns such x (x is certain).uint64_tquery_min(uint64_tword){intnode=ROOT;uint64_tval=0;for(inti=BITS-1;i>=0;i--){intgo_bit=word>>i&1;if(tr[node].child[go_bit]==-1){go_bit^=1;}val|=1ull<<go_bit;node=tr[node].child[go_bit];}returnval;}// Find such an x inserted in the trie that word ^ x is maximized.// Returns such x (x is certain).uint64_tquery_max(uint64_tword){intnode=ROOT;uint64_tval=0;for(inti=BITS-1;i>=0;i--){intgo_bit=(word>>i&1)^1;if(tr[node].child[go_bit]==-1){go_bit^=1;}val|=1ull<<go_bit;node=tr[node].child[go_bit];}returnval;}// CF1983F: Find such an x inserted in the trie that word ^ x < upper_bound// Returns a pair {min_index, max_index} of x.std::pair<int,int>query_ub(uint64_tword,uint64_tupper_bound){intmn=INF,mx=-INF,node=ROOT;for(inti=BITS-1;i>=0;i--){intword_bit=word>>i&1;// digit i of wordintub_bit=upper_bound>>i&1;// digit i of ubif(ub_bit==1&&tr[node].child[word_bit]!=-1){// if digit i of ub is 1, then we can choose either// the subtree of word_bit or word_bit ^ 1.mn=std::min(mn,tr[tr[node].child[word_bit]].min_index);mx=std::max(mx,tr[tr[node].child[word_bit]].max_index);}// else if digit i of ub is 0, then we can only choose// the subtree of word_bit. (otherwise, we will violate the range)node=tr[node].child[word_bit^ub_bit];if(node==-1)break;}return{mn,mx};}};#endif // AFDS_BINARY_TRIE
#line 1 "src/alfred/data_structure/binary-trie.hpp"
// TODO: Require to be rewritten.// Thanks neal for this template.#include<array>
#include<cstdint>
#include<vector>constintBITS=30;constintINF=1e9+7;structBinaryTrie{// 01-TriestaticconstintALPHABET=2;structNode{constintparent;intwords_here=0;// How many words EXACTLY here.intstarting_with=0;// How many words have the PREFIX of this node.intmin_index=INF;// The minimum index of words which have PREFIX of this node.intmax_index=-INF;// The maximum index of words which have PREFIX of this node.std::array<int,ALPHABET>child;Node(intp=-1):parent(p){child.fill(-1);}};staticconstintROOT=0;std::vector<Node>tr={Node()};BinaryTrie(inttotal_length=-1){// Sum of |s|, leave -1 if don't know.if(total_length>=0)tr.reserve(total_length+1);}// Returns the Node reference of word.// NOTICE: this function creates a new Node if word isn't in the trie.Node&operator[](uint64_tword){returntr[build(word,0)];}// Get or create c-th (c = 0, 1) child of node// Returns BinaryTrie node.intget_or_create_child(intnode,intc){if(tr[node].child[c]==-1){tr[node].child[c]=(int)tr.size();tr.push_back(Node(node));}returntr[node].child[c];}// Build rootpath of word, insert delta (个) words// Returns BinaryTrie node.intbuild(uint64_tword,intdelta){intnode=ROOT;for(inti=BITS-1;i>=0;i--){tr[node].starting_with+=delta;node=get_or_create_child(node,word>>i&1);}tr[node].starting_with+=delta;returnnode;}// Insert a word with the index of index, INF if index is unknown.// Returns BinaryTrie node.intinsert(uint64_tword,intindex=INF){intnode=build(word,1);tr[node].words_here+=1;for(intx=node;x!=-1;x=tr[x].parent){if(index!=INF){tr[x].min_index=std::min(tr[x].min_index,index);tr[x].max_index=std::max(tr[x].max_index,index);}}returnnode;}// Find such an x inserted in the trie that word ^ x is minimized.// Returns such x (x is certain).uint64_tquery_min(uint64_tword){intnode=ROOT;uint64_tval=0;for(inti=BITS-1;i>=0;i--){intgo_bit=word>>i&1;if(tr[node].child[go_bit]==-1){go_bit^=1;}val|=1ull<<go_bit;node=tr[node].child[go_bit];}returnval;}// Find such an x inserted in the trie that word ^ x is maximized.// Returns such x (x is certain).uint64_tquery_max(uint64_tword){intnode=ROOT;uint64_tval=0;for(inti=BITS-1;i>=0;i--){intgo_bit=(word>>i&1)^1;if(tr[node].child[go_bit]==-1){go_bit^=1;}val|=1ull<<go_bit;node=tr[node].child[go_bit];}returnval;}// CF1983F: Find such an x inserted in the trie that word ^ x < upper_bound// Returns a pair {min_index, max_index} of x.std::pair<int,int>query_ub(uint64_tword,uint64_tupper_bound){intmn=INF,mx=-INF,node=ROOT;for(inti=BITS-1;i>=0;i--){intword_bit=word>>i&1;// digit i of wordintub_bit=upper_bound>>i&1;// digit i of ubif(ub_bit==1&&tr[node].child[word_bit]!=-1){// if digit i of ub is 1, then we can choose either// the subtree of word_bit or word_bit ^ 1.mn=std::min(mn,tr[tr[node].child[word_bit]].min_index);mx=std::max(mx,tr[tr[node].child[word_bit]].max_index);}// else if digit i of ub is 0, then we can only choose// the subtree of word_bit. (otherwise, we will violate the range)node=tr[node].child[word_bit^ub_bit];if(node==-1)break;}return{mn,mx};}};