可持久化Trie
阿新 • • 發佈:2018-12-30
末尾 麻煩 lan 理解 esp 一段 直接 span www. 。
例題:luoguP4735
可持久化\(Trie\)嘛,就和可持久化線段樹差不多。這篇文章只是借例題講一講如何截取一段時間的信息。
直接講題大家就可理解。
題目大意
有兩種操作,第一種在數組末尾加上一個數,第二種在\(l\leqslant p\leqslant r\)中求最大的$ a[p] \bigoplus a[ p + 1 ] \bigoplus ...\bigoplus a[ N ] \bigoplus x$。
問題分析
我們先求一個異或前綴和,記為\(A\)。那麽第二問就變成了求在\(l-1 \leqslant p \leqslant r-1\)中最大的\(A[p]\bigoplus A[N]\bigoplus x\)
然後麻煩之處就是在\(p\)的範圍限制了。
右端點限制非常方便,左端點的限制可以這樣解決:
我們記錄一個數組\(Cnt\),\(Cnt_i\)表示\(Trie\)中節點\(i\)被多少個數經過。那麽我們只要判斷\(Cnt_{Right}-Cnt_{Left}\)就可以知道在這個範圍內是否可行。
解釋得不是很清楚,大家根據程序理解一下吧。
參考程序
// luogu-judger-enable-o2 #include <bits/stdc++.h> #define LL long long using namespace std; const int MaxBit = 24; const int MaxN = 600010; int N, M, A[ MaxN ]; int Trie[ MaxBit * MaxN ][ 2 ], Cnt[ MaxBit * MaxN ], Used, Root[ MaxN ]; char Ch[ 10 ]; inline void Add( int Index, int History, int Bit, int Value ); inline int Query( int Left, int Right, int Bit, int Value ); int main() { scanf( "%d%d", &N, &M ); Root[ 0 ] = ++Used; Add( Root[ 0 ], 0, MaxBit, 0 ); int i; for( i = 1; i <= N; ++i ) scanf( "%d", &A[ i ] ); for( i = 1; i <= N; ++i ) A[ i ] = A[ i - 1 ] ^ A[ i ]; for( i = 1; i <= N; ++i ) { Root[ i ] = ++Used; Add( Root[ i ], Root[ i - 1 ], MaxBit, A[ i ] ); } for( i = 1; i <= M; ++i ) { scanf( "%s", Ch ); if( Ch[ 0 ] == 'A' ) { scanf( "%d", &A[ ++N ] ); A[ N ] = A[ N - 1 ] ^ A[ N ]; Root[ N ] = ++Used; Add( Root[ N ], Root[ N - 1 ], MaxBit, A[ N ] ); } if( Ch[ 0 ] == 'Q' ) { int l, r, x; scanf( "%d%d%d", &l, &r, &x ); x ^= A[ N ]; --l; --r; if( l == 0 ) printf( "%d\n", Query( 0, Root[ r ], MaxBit, x ) ); else printf( "%d\n", Query( Root[ l - 1 ], Root[ r ], MaxBit, x ) ); } } return 0; } inline void Add( int Index, int History, int Bit, int Value ) { if( Bit < 0 ) return; int T = ( Value >> Bit ) & 1; Trie[ Index ][ !T ] = Trie[ History ][ !T ]; Trie[ Index ][ T ] = ++Used; Cnt[ Trie[ Index ][ T ] ] = Cnt[ Trie[ History ][ T ] ] + 1; Add( Trie[ Index ][ T ], Trie[ History ][ T ], Bit - 1, Value ); return; } inline int Query( int Left, int Right, int Bit, int Value ) { if( Bit < 0 ) return 0; int T = ( Value >> Bit ) & 1; if( Cnt[ Trie[ Right ][ !T ] ] - Cnt[ Trie[ Left ][ !T ] ] > 0 ) return ( 1 << Bit ) + Query( Trie[ Left ][ !T ], Trie[ Right ][ !T ], Bit - 1, Value ); else return Query( Trie[ Left ][ T ], Trie[ Right ][ T ], Bit - 1, Value ); }
可持久化Trie