1. 程式人生 > >XJOI 異或 (Trie樹)

XJOI 異或 (Trie樹)

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>
using
namespace 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,int
x,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樹)