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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

2021牛客暑期多校训练营4 E-Tree Xor(异或+思维+区间交 or Trie树)

發(fā)布時間:2023/12/3 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 2021牛客暑期多校训练营4 E-Tree Xor(异或+思维+区间交 or Trie树) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

E-Tree Xor

首先不考慮區(qū)間限制條件,我們給定其中一個點的權值后,那么其他點的權值也就確定。比如 val1=0\text{val}_1=0val1?=0,即可通過變得限制求出其他點valu\text{val}_uvalu?,而且不難發(fā)現(xiàn)如果val1=0⊕a\text{val}_1=0\oplus aval1?=0a那么其余點的權值valu=0⊕a\text{val}_u=0\oplus avalu?=0a

下面記valu\text{val}_uvalu?為當val1=0\text{val}_1=0val1?=0時,u點的權值。

于是問題轉化為求出滿足下面區(qū)間限制aaa的個數(shù)。
L1≤val1⊕a≤R1L2≤val2⊕a≤R2…Ln≤valn⊕a≤Rn\text L_1\leq \text{val}_1\oplus a\leq \text R_1\\\text L_2\leq \text{val}_2\oplus a\leq \text R_2\\ \dots\\ \text L_n\leq \text{val}_n\oplus a\leq \text R_n L1?val1?aR1?L2?val2?aR2?Ln?valn?aRn?

考慮其中一種限制直觀的想法是Lu≤valu⊕a≤Ru?L1⊕val1≤a≤R1⊕val1\text L_u\leq \text{val}_u\oplus a\leq \text R_u\Rightarrow \text L_1\oplus \text{val}_1\ \leq a\leq \text R_1\oplus \text{val}_1Lu?valu?aRu??L1?val1??aR1?val1?不難發(fā)現(xiàn)上面轉化是錯誤的,而且可以發(fā)現(xiàn)aaa的區(qū)間是不連續(xù)的!!!需要找出這些不連續(xù)的區(qū)間!

于是就很難處理,后面就是講題人的做法(真滴強)


我們可以利用 [0,230?1][0,2^{30}-1][0,230?1] 的線段樹, 把 [Li,Ri][L_i , R_i][Li?,Ri?] 分成 log?W\log WlogW個連續(xù)的區(qū)間, 且每個區(qū)間的形式是 : [???00…00,???11…11][***00\dots00,***11\dots 11][???0000,???1111], 這樣的區(qū)間異或上 vali\text{val}_ivali?仍然還是一個區(qū)間

不妨設???***???的數(shù)量是k

不難發(fā)現(xiàn)區(qū)間[???00…00,???11…11][***00\dots00,***11\dots 11][???0000,???1111]抑或上vali\text{val}_ivali?的區(qū)間是[???00…00,???,11…11][- - -00\dots00,---,11\dots11][???0000,???,1111]
其中???---???(???00…00)⊕vali(***00\dots00)\oplus \text{val}_i(???0000)vali?的前kkk位的值
比如:[10100000,10101111][\color{Blue}{1010} \color{Red}{0000},\color{Blue}{1010} \color{Red}{1111}][10100000,10101111]⊕10011010?\oplus\color{Blue}{1001} \color{Red}{1010}\Rightarrow10011010? [00110000,00111111][\color{Blue}{0011} \color{Red}{0000},\color{Blue}{0011} \color{Red}{1111}][00110000,00111111]

藍色部分異或0011=1010⊕0011\color{Blue}0011=1010\oplus00110011=10100011原紅色部分不變,稍微思考一下就知道為什么了。

通過上面操作成功找出這些不連續(xù)的區(qū)間!!!


然后就sort區(qū)間差分亂搞就行。時間復雜度2log,可以用線段樹維護所有不合法區(qū)間的并集,把不合法的區(qū)間標記為1,把時間復雜度降為1log

Code1

#include<bits/stdc++.h> using namespace std; using ll=long long; template <class T=int> T rd() {T res=0;T fg=1;char ch=getchar();while(!isdigit(ch)) {if(ch=='-') fg=-1;ch=getchar();}while( isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();return res*fg; } const int N=100010; int h[N],e[2*N],ne[2*N],w[2*N],idx; void add(int a,int b,int c){e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;} int L[N],R[N]; int val[N]; struct node {int l,r; }tree[N*40]; int rt,cnt,n; vector<pair<int,int>> vec; void insert(int &u,int l,int r,int L,int R,int val) {if(!u) u=++cnt;if(L<=l&&r<=R){int ql=l^(val&(~(r-l)));//異或之后的區(qū)間[ql,qr]int qr=ql+r-l;vec.push_back({ql,1});vec.push_back({qr+1,-1});return;}int mid=l+r>>1;if(L<=mid) insert(tree[u].l,l,mid,L,R,val);if(R>mid)insert(tree[u].r,mid+1,r,L,R,val); }void dfs(int u,int fa) {insert(rt,0,(1<<30)-1,L[u],R[u],val[u]);for(int i=h[u];i!=-1;i=ne[i]){int v=e[i];if(v==fa) continue;val[v]=val[u]^w[i];dfs(v,u);} } int solve() {sort(vec.begin(),vec.end());vec.push_back({1<<30,0});int ans=0;int cur=0;for(int i=0;i<vec.size()-1;i++){cur+=vec[i].second;if(cur==n) ans+=vec[i+1].first-vec[i].first;}return ans; } int main() {n=rd();for(int i=1;i<=n;i++) L[i]=rd(),R[i]=rd();memset(h,-1,sizeof h);for(int i=1;i<n;i++){int u=rd(),v=rd(),w=rd();add(u,v,w),add(v,u,w);}dfs(1,0);printf("%d\n",solve()); }

比較容易想到的做法就是我們需要求
L1≤val1⊕a≤R1L2≤val2⊕a≤R2…Ln≤valn⊕a≤Rn\text L_1\leq \text{val}_1\oplus a\leq \text R_1\\\text L_2\leq \text{val}_2\oplus a\leq \text R_2\\ \dots\\ \text L_n\leq \text{val}_n\oplus a\leq \text R_n L1?val1?aR1?L2?val2?aR2?Ln?valn?aRn?
轉化成
[val1⊕a≤R1]?[val1⊕a<L1][val2⊕a≤R2]?[val2⊕a<L2]…[valn⊕a≤Rn]?[valn⊕a<Ln][\text{val}_1\oplus a\leq \text R_1]?[\text{val}_1\oplus a< \text L_1]\\ [\text{val}_2\oplus a\leq \text R_2]?[\text{val}_2\oplus a< \text L_2]\\ \dots\\ [\text{val}_n\oplus a\leq \text R_n]?[\text{val}_n\oplus a< \text L_n] [val1?aR1?]?[val1?a<L1?][val2?aR2?]?[val2?a<L2?][valn?aRn?]?[valn?a<Ln?]
上面的?理解為兩個集合相減。

實際上我需要求的就是⊕a≤b\oplus a\leq bab的區(qū)間,顯然字典樹可以做,相當于求⊕a≤b\oplus a\leq bab的數(shù)有哪些,和第二次杭電I love counting求的步驟一樣,在Trie樹上討論一下就行。

Code2

#include<bits/stdc++.h> using namespace std; using ll=long long; template <class T=int> T rd() {T res=0;T fg=1;char ch=getchar();while(!isdigit(ch)) {if(ch=='-') fg=-1;ch=getchar();}while( isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();return res*fg; } const int N=100010; int h[N],e[2*N],ne[2*N],w[2*N],idx; void add(int a,int b,int c){e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;} int L[N],R[N]; int val[N]; struct node {int l,r; }tree[N*40]; int rt,cnt,n; vector<pair<int,int>> seg[2]; void query(int k,int a,int b)// x^a<=b {int u=rt;int cur=0;for(int i=29;i>=0;i--)//30位{int ai=a>>i&1;int bi=b>>i&1;if(bi==1) //b=1{if(ai==0) {seg[k].push_back({cur,cur+(1<<i)-1});cur+=1<<i;if(!tree[u].r) tree[u].r=++cnt;u=tree[u].r;}else{seg[k].push_back({cur+(1<<i),cur+(1<<i)+(1<<i)-1});if(!tree[u].l) tree[u].l=++cnt;u=tree[u].l;}}else{if(ai==0){if(!tree[u].l) tree[u].l=++cnt;u=tree[u].l;}else {cur+=1<<i;if(!tree[u].r) tree[u].r=++cnt;u=tree[u].r;}}}seg[k].push_back({cur,cur}); } void dfs(int u,int fa) {for(int i=h[u];i!=-1;i=ne[i]){int v=e[i];if(v==fa) continue;val[v]=val[u]^w[i];dfs(v,u);} } int solve() {vector<pair<int,int>>vec;for(auto t:seg[0]) {vec.push_back({t.first,-1});vec.push_back({t.second+1,+1});}for(auto t:seg[1]) {vec.push_back({t.first,+1});vec.push_back({t.second+1,-1});}sort(vec.begin(),vec.end());vec.push_back({1<<30,0});int ans=0;int cur=0;for(int i=0;i<vec.size()-1;i++){cur+=vec[i].second;if(cur==n) ans+=vec[i+1].first-vec[i].first;}return ans; } int main() {n=rd();for(int i=1;i<=n;i++) L[i]=rd(),R[i]=rd();memset(h,-1,sizeof h);for(int i=1;i<n;i++){int u=rd(),v=rd(),w=rd();add(u,v,w),add(v,u,w);}dfs(1,0);for(int i=1;i<=n;i++) {if(L[i]>0) query(0,val[i],L[i]-1);query(1,val[i],R[i]);}printf("%d\n",solve()); }

其實仔細分析應該能寫出Trie樹的做法,不過當時沒有分析出來啊www

要加油哦~

總結

以上是生活随笔為你收集整理的2021牛客暑期多校训练营4 E-Tree Xor(异或+思维+区间交 or Trie树)的全部內容,希望文章能夠幫你解決所遇到的問題。

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