01字典樹加強版HDU 5536
阿新 • • 發佈:2018-11-08
01字典樹加強版HDU 5536
http://acm.hdu.edu.cn/showproblem.php?pid=5536
-
簡化版題意:
在一個數組中找出 (s[i]+s[j])^s[k] 最大的值,其中 i、j、k 各不相同。 -
這個題目我們就不能直接套用模板了,問題出在哪裡?是因為i、j、k不能相同,所以直接查詢tire樹會出現問題。怎麼辦?一個很直觀的想法是刪除。對k建trie樹,列舉i、j,然後將i、j在trie樹中刪除。
-
考慮如何刪除,我們用一個num陣列記錄每一個結點出現的次數(注意是每一個結點而不是結尾的結點,因為如果i,j兩個位置的數字不能使用,那麼在tire樹上所有關於他的結點都不能使用),在每次insert的時候增加num,在每次刪除的時候減少num,在最後查詢的時候判斷num是否為0代表當前樹上這個結點是否可以使用。說到這裡,這個題的大致思路就說完了,下面直接上程式碼。
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> #define mk(a,b) make_pair(a,b) #define ll long long #define N 1010 using namespace std; ll tot,ch[N*32][3],val[N*32],num[N*32],t,a[N]; void init() { tot=1; ch[0][1]=0;ch[0][0]=0; } void insert(ll x) { ll u=0; for(ll i=32;i>=0;i--) { ll v=(x>>i)&1; if(!ch[u][v]) { ch[tot][0]=0;ch[tot][1]=0; val[tot]=0; num[tot]=0; ch[u][v]=tot++; } u=ch[u][v]; num[u]++; } val[u]=x; } void del(ll x,ll add) { ll u=0; for(ll i=32;i>=0;i--) { ll v=(x>>i)&1; u=ch[u][v]; num[u]+=add; } } ll query(ll x) { ll u=0; for(ll i=32;i>=0;i--) { ll v=(x>>i)&1; if(ch[u][v^1]&&num[ch[u][v^1]]) u=ch[u][v^1]; else u=ch[u][v]; } return x^val[u]; } int main() { scanf("%lld",&t); for(ll k=1;k<=t;k++) { ll n,ans=0; init(); scanf("%lld",&n); for(ll i=1;i<=n;i++) { scanf("%lld",&a[i]); insert(a[i]); } for(ll i=1;i<=n;i++) for(ll j=i+1;j<=n;j++) { del(a[i],-1);del(a[j],-1); ans=max(ans,query(a[i]+a[j])); insert(a[i]);insert(a[j]); } printf("%lld\n",ans); } return 0; }