#pragma once
#include<vector>namespacehaar_lib{template<typenameT,unsignedintB>classbinary_trie{public:usingvalue_type=T;protected:structnode{intcount;node*ch[2];node():count(0){ch[0]=ch[1]=nullptr;}};node*root_=nullptr;protected:intcount(node*t)const{returnt?t->count:0;}intcount(node*t,Tval,unsignedintdepth=1)const{if(nott)return0;if(depth>B)returnt->count;intb=(val>>(B-depth))&1;returncount(t->ch[b],val,depth+1);}public:intcount(Tval)const{returncount(root_,val);}public:intsize()const{returnroot_?root_->count:0;}boolempty()const{returnnotroot_;}protected:voidto_list(node*t,Tval,std::vector<T>&ret)const{if(nott)return;if(nott->ch[0]andnott->ch[1])for(inti=0;i<t->count;++i)ret.push_back(val);if(t->ch[0])to_list(t->ch[0],val<<1,ret);if(t->ch[1])to_list(t->ch[1],(val<<1)|1,ret);}public:std::vector<T>to_list()const{std::vector<T>ret;to_list(root_,0,ret);returnret;}protected:node*insert(node*t,Tval,unsignedintdepth=1){if(nott)t=newnode();++(t->count);if(depth>B)returnt;intb=(val>>(B-depth))&1;t->ch[b]=insert(t->ch[b],val,depth+1);returnt;}public:voidinsert(Tval){root_=insert(root_,val);}protected:node*erase(node*t,Tval,unsignedintdepth=1){if(nott)returnt;--(t->count);if(t->count==0)returnnullptr;if(depth>B)returnt;intb=(val>>(B-depth))&1;t->ch[b]=erase(t->ch[b],val,depth+1);returnt;}public:voiderase(Tval){root_=erase(root_,val);}protected:Tmin_element(node*t,Tdiff,unsignedintdepth=1)const{if(depth>B)return0;intb=(diff>>(B-depth))&1;b^=nott->ch[b];returnmin_element(t->ch[b],diff,depth+1)|(b<<(B-depth));}public:Tmin_element(Tdiff=0)const{returnmin_element(root_,diff);}protected:Tmax_element(node*t,Tdiff,unsignedintdepth=1)const{if(depth>B)return0;intb=not((diff>>(B-depth))&1);b^=nott->ch[b];returnmax_element(t->ch[b],diff,depth+1)|(b<<(B-depth));}public:Tmax_element(Tdiff=0)const{returnmax_element(root_,diff);}protected:Tat(node*t,intindex,unsignedintdepth=1)const{if(depth>B)return0;intc=count(t->ch[0]);if(t->ch[0]andindex<c)returnat(t->ch[0],index,depth+1);elsereturnat(t->ch[1],index-c,depth+1)|((T)1<<(B-depth));}public:Tat(intindex)const{returnat(index);}protected:intlower_bound(node*t,Tval,unsignedintdepth=1)const{if(nott)return0;intb=(val>>(B-depth))&1;return(b?count(t->ch[0]):0)+lower_bound(t->ch[b],val,depth+1);}public:intlower_bound(Tval)const{returnlower_bound(root_,val);}intupper_bound(Tval)const{returnlower_bound(root_,val+1);}};}// namespace haar_lib