中石油训练赛 - 腿部挂件(可持久化字典树)
題目描述
Jim是一個熱愛打游戲的小伙子,可惜他的游戲水平不太行,以至于經常在游戲里被別人欺負。而且Jim不僅游戲玩的菜,他還很愛噴人,但是由于自己的垃圾操作,他又噴不過別人。為了改善這種局面,Jim決定成為一個腿部掛件(俗稱抱大腿)。
已知現在有N個選手可供Jim選擇,每位選手的能力值為 ai。N位選手不一定每位選手都有時間配Jim玩游戲而且Jim的狀態也時好時壞,所以Jim有Q個詢問,每個詢問是3個數X、L、R,求第L個人到第R個人這R-L+1個人中與Jim配合后的能力值最大是多少,Jim 與第i位選手配合后的能力值為ai與X進行異或運算(Xor)。
輸入
第1行:2個數N, Q中間用空格分隔,分別表示選手個數及查詢的數量(1≤N≤200000,1≤Q≤200000)。?
第2 行:共N個數為每個選手能力值中間用空格分隔,對應ai(0≤a[i]≤10^9)。?
第N+2 - N+Q+1行:每行3個數X, L, R,中間用空格分隔。(0≤X≤10^9,0≤L≤R<N)
輸出
輸出共Q行,對應每次詢問所能得到的最大能力值。
樣例輸入?
9 8 2 15 4 12 0 6 0 16 12 2 2 5 4 8 8 16 5 8 16 6 8 1 0 5 12 3 4 15 1 1 5 0 4樣例輸出
14 8 28 28 14 12 0 10提示
對于第一個詢問 2 與{4 12 0} 最大的能力值組合為 2 xor 12 = 14 注意 L R標號從 0 開始
對于20%的數據保證 (1≤N≤5000, 1≤Q≤5000)。?
對于45%的數據保證 (1≤N≤50000, 1≤Q≤50000)。?
對于100%的數據保證 (1≤N≤200000, 1≤Q≤200000)。
題目大意:給出n個數,在給出m個查詢,每次查詢的形式是x,l,r,輸出在閉區間[l,r]內與x異或后最大的結果
題目分析:這個題如果是按點給分制的題目,我們完全可以暴力跑過數據比較水的測試點,但當n和m比較大的時候,n*n的暴力就顯然無法通過所有測試點了,因為之前學了一波如何線性查找任意兩個數異或的最大值,知道了字典樹可以處理異或最大值或最小值的問題,這個題也是那種問題的進階版,因為涉及到了區間,所以也就需要將字典樹可持久化,那么這個題目的正解也就是可持久化01字典樹,構造完字典樹后對應輸出即可,第一次接觸,掛個板子,以后若有需要再深入學習
代碼:
#include<iostream> #include<cstdlib> #include<string> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<cmath> #include<cctype> #include<stack> #include<queue> #include<list> #include<vector> #include<set> #include<map> #include<sstream> #include<unordered_map> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=2e5+100;int trie[N*32][2];int sum[N*32];int root[N];int cnt=1;//這里注意一定要從1開始,因為所有trie的初始化為0,如果第0號節點設上數了,會對后續節點產生影響void insert(int pre,int& cur,int step,int x) {cur=cnt++;//新建一個版本 trie[cur][0]=trie[pre][0];trie[cur][1]=trie[pre][1];//復制前一個節點的信息sum[cur]=sum[pre]+1;//加上當前新建的鏈if(step<0)//x到最后一位了return;int to=(x>>step)&1;//提取出x的當前位insert(trie[pre][to],trie[cur][to],step-1,x);//遞歸建樹 }int search(int l,int r,int step,int x) {if(step<0)return 0;int to=(x>>step)&1;if(sum[trie[r][!to]]>sum[trie[l][!to]])//說明有可以異或的這條路 return search(trie[l][!to],trie[r][!to],step-1,x)+(1<<step);elsereturn search(trie[l][to],trie[r][to],step-1,x); } int main() { // freopen("input.txt","r",stdin);int n,m;scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){int num;scanf("%d",&num);insert(root[i-1],root[i],30,num);}while(m--){int l,r,x;scanf("%d%d%d",&x,&l,&r);l++,r++;printf("%d\n",search(root[l-1],root[r],30,x));}return 0; }?
總結
以上是生活随笔為你收集整理的中石油训练赛 - 腿部挂件(可持久化字典树)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PAT (Advanced Level)
- 下一篇: HDU - 1358 Period(KM