【題解】CF817E Choosing The Commander

題目戳我

\(\text{Solution:}\)

看到異或(以及E題的位置)想到\(01Trie.\)

考慮維護一個\(sum\)數組代表樹上\(x\)點內有多少數字。那麼添加操作每次走一個二進制位的時候更新\(sum+1,\)刪除時更新\(sum-1.\)

考慮如何詢問:

先讀好題,上面說的是異或\(p_i\)小於\(l_i\)

所以這裏\(l_i\)的二進制位起到了最主要的限制作用。

\(l_i\)的這一位是\(1,\)則我們加上\(p_i\)這一位所對應相同的節點的\(sum\)(保證異或這一位是\(0,\)小於\(l_i\)

\(l_i\)的這一位是\(0\)也就沒有必要累加答案了,因爲這裏只有一種異或法則:令這一位爲\(0.\)

考慮繼續走:若\(l_i\)這一位是\(0\)我們就可以走到異或\(p_i\)這一位爲\(0\)的位置;反之,由於我們之前計算過貢獻,所以我們走到異或\(p_i\)這一位爲\(1\)的位置。

時間複雜度\(O(n\log 10^8).\)

#include<bits/stdc++.h>
using namespace std;
int Q,T[3000010][2],n;
int tot=1,sum[3000010];
inline void insert(int v,int vv){
	int p=1;
	for(int i=30;i>=0;--i){
		int x=v>>i&1;
		sum[p]+=vv;
		if(!T[p][x])T[p][x]=++tot;
		p=T[p][x];
	}
	sum[p]+=vv;
}
int query(int ch,int v){
	int ans=0,p=1;
	for(int i=30;i>=0;--i){
		int vp=v>>i&1;
		int chp=ch>>i&1;
		if(chp<vp)ans+=sum[T[p][0]];
		if(vp&&chp)ans+=sum[T[p][1]];
		if(!vp)p=T[p][chp];
		else p=T[p][chp^1];
	}
	return ans;
}
int main(){
	scanf("%d",&n);
	while(n--){
		int x,y,z;
		scanf("%d%d",&x,&y);
		if(x==1)insert(y,1);
		if(x==2)insert(y,-1);
		if(x==3){
			scanf("%d",&z);
			printf("%d\n",query(y,z));
		}
	}
	return 0;
}

注意事項:\(Trie\)最好以\(1\)爲根,有時候會出現一些不知道什麼鬼的錯誤)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章