XJOI 異或 (Trie樹)
阿新 • • 發佈:2017-09-07
log for 為我 its 區間 scanf tle ear name
這題對我來說真是一塊大蛋糕,又是一座大山
大蛋糕是因為算法很好胡
大山是因為我實在是太菜
然後我就在考場上續了兩個小時
/-------------------------------------------/
這題算法不算難想,但對我來說挺難打
1.將ai拆成二進制,由高位到低位加入Trie樹,不足的補前導0,每個節點的ans統計子樹中有多少個值
2.讀入區間l,r拆成區間1-r+1,1-l處理
3.search時統計小於limit的數量
4.如果pos的一個子樹內異或x最大值之差小於limit,就直接加上ans[pos]
5.如果大於等於limit就遞歸處理子問題
#include<bits/stdc++.h> usingnamespace std; int a[32],n,m,x,l,r,tot,ch[5000000][2],ans[5000000]; void add(int x){ int pos=1; ans[pos]++; for (int i=1; i<=31; i++){ int j=x/a[i]; x%=a[i]; if (ch[pos][j]==0) ch[pos][j]=++tot; pos=ch[pos][j]; ans[pos]++; } } int search(int s,int ii,intx,int limit){ int pos=s,res=0; for (int i=ii; i<=31; i++){ int j=x/a[i]; x%=a[i]; if (a[i]<=limit){ if (ch[pos][j]) res+=ans[ch[pos][j]]; if (ch[pos][j^1]) res+=search(ch[pos][j^1],i+1,x,limit-a[i]); break; } if(ch[pos][j]) pos=ch[pos][j]; else break; } return res; } int main(){ tot=1; a[31]=1; for (int i=30; i>=1; i--) a[i]=a[i+1]*2; scanf("%d%d",&n,&m); for (int i=1; i<=n; i++){ scanf("%d",&x); add(x); } while (m--){ scanf("%d%d%d",&x,&l,&r); printf("%d\n",search(1,1,x,r+1)-search(1,1,x,l)); } }
XJOI 異或 (Trie樹)