日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[学习笔记]我们追过的神奇异或(Trie树系列)

發(fā)布時(shí)間:2023/12/20 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [学习笔记]我们追过的神奇异或(Trie树系列) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

引言

剛學(xué)了\(Trie\)樹,寫篇博客鞏固一下。

題目

首先安利一發(fā)\(Trie\)樹模板

1、Phone List

2、The XOR largest pair

3、The xor-longest Path

4、Codechef REBXOR

第一題不難,但是我用的是暴力。

構(gòu)造一棵\(Trie\)樹,然后把字符串長度從大到小排序,然后按順序插入。若在插入的時(shí)候\(Trie\)樹結(jié)點(diǎn)一直不為空,那么該串為其的子串。

\(Code\ Below:\)

#include <bits/stdc++.h> using namespace std; int n,trie[100010][10],ans,tot; char s[100010][15]; struct node{int len,id; }l[100010]; void insert(int k){int len=strlen(s[k]),p=0,b=0;for(int i=0;i<len;i++){if(trie[p][s[k][i]-'0']==-1) {trie[p][s[k][i]-'0']=++tot;b=1;}p=trie[p][s[k][i]-'0'];}if(b==0) ans=1; } bool cmp(node a,node b){return a.len>b.len; } int main() {int t;scanf("%d",&t);while(t--){memset(trie,-1,sizeof(trie));scanf("%d",&n);ans=0;tot=0;for(int i=1;i<=n;i++){scanf("%s",s[i]);l[i].len=strlen(s[i]);l[i].id=i;}sort(l+1,l+n+1,cmp);for(int i=1;i<=n;i++){if(ans==0) insert(l[i].id);}if(ans==1) printf("NO\n");else printf("YES\n");}return 0; }

第二題構(gòu)造一棵\(Trie\)樹,然后根據(jù)異或的運(yùn)算規(guī)則,盡量當(dāng)前的值與結(jié)點(diǎn)的值不一樣。
此題是二三題的基礎(chǔ)。

\(Code\ Below:\)

#include <cstdio> int n,trie[100010*31][2],ans=0,val,tot=0; int max(int a,int b){return a>b?a:b;} int search(int x){int p=0,num=0,c;for(int i=31;i>=0;i--){c=(x>>i)&1;if(trie[p][c^1])p=trie[p][c^1],num=num<<1|1;else p=trie[p][c],num=num<<1;}return num; } void insert(int x){int p=0,c;for(int i=31;i>=0;i--){c=(x>>i)&1;if(!trie[p][c]) trie[p][c]=++tot;p=trie[p][c];} } int main() {scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&val);ans=max(ans,search(val));insert(val);}printf("%d\n",ans);return 0; }

定義前綴異或和\(sum[1..i]=a[1]\)^\(...\)^\(a[i]\),\(v[i..j]=a[i]\)^\(a[i+1]\)^\(...\)^\(a[j]\),則\(v[i..j]=sum[1..i] * sum[1..j]\)

由于\(a^a=0,0^a=a,\)所以異或兩次值不變。

那么預(yù)處理出樹上前綴異或和(即到根的前綴異或和),跑一遍\(The\ XOR\ largest\ pair\)

\(Code\ Below:\)

#include <cstdio> int n,trie[100010*31][2],ans=0,a[100010],val,tot=0,t=0,head[100010]; int max(int a,int b){return a>b?a:b;} struct node{int to,val,next; }e[100010*2]; void add(int x,int y,int w){e[++t].to=y;e[t].val=w;e[t].next=head[x];head[x]=t; } void dfs(int x,int fa,int now){a[x]=now;for(int i=head[x];i;i=e[i].next){int y=e[i].to;if(y==fa) continue;dfs(y,x,now^e[i].val);} } int search(int x){int p=0,num=0,c;for(int i=31;i>=0;i--){c=(x>>i)&1;if(trie[p][c^1])p=trie[p][c^1],num=num<<1|1;else p=trie[p][c],num=num<<1;}return num; } void insert(int x){int p=0,c;for(int i=31;i>=0;i--){c=(x>>i)&1;if(!trie[p][c]) trie[p][c]=++tot;p=trie[p][c];} } int main() {scanf("%d",&n);for(int i=1;i<n;i++){int x,y,w;scanf("%d%d%d",&x,&y,&w);add(x,y,w);add(y,x,w);}dfs(1,1,0);for(int i=1;i<=n;i++){ans=max(ans,search(a[i]));insert(a[i]);}printf("%d\n",ans);return 0; }

第四題預(yù)處理出前綴異或和和后綴異或和,然后用\(O(n)\)的時(shí)間求最大值

\(Code\ Below:\)

#include <cstdio> int n,trie[400010*31][2],ans=0,val,tot=0,a[100010],l[400010],r[400010]; int max(int a,int b){return a>b?a:b;} int search(int x){int p=0,num=0,c;for(int i=31;i>=0;i--){c=(x>>i)&1;if(trie[p][c^1])p=trie[p][c^1],num=num<<1|1;else p=trie[p][c],num=num<<1;}return num; } void insert(int x){int p=0,c;for(int i=31;i>=0;i--){c=(x>>i)&1;if(!trie[p][c]) trie[p][c]=++tot;p=trie[p][c];} } int main() {scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&a[i]);int now=0;insert(now);for(int i=1;i<=n;i++){now^=a[i];l[i]=max(l[i-1],search(now));insert(now);}now=0;insert(now);for(int i=n;i>=1;i--){now^=a[i];r[i]=max(r[i+1],search(now));insert(now);}for(int i=1;i<n;i++){ans=max(ans,l[i]+r[i+1]);}printf("%d\n",ans);return 0; }

轉(zhuǎn)載于:https://www.cnblogs.com/owencodeisking/p/9735350.html

總結(jié)

以上是生活随笔為你收集整理的[学习笔记]我们追过的神奇异或(Trie树系列)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。