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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

Tree Xor(未完全搞定)

發(fā)布時間:2023/12/3 编程问答 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Tree Xor(未完全搞定) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Tree Xor

題意:

一顆有n個點的樹,邊權給出,第i個節(jié)點的權值為Wi,但并不知道Wi,只知道Wi在[Li,Ri],邊權等于兩端點的異或值
問W序列有多少可能

題解:

如果我們知道一個點的值,就可以推出其他所有點的值。
現(xiàn)在我們令w[1]=0,解出剩下的w,如果令w[1] = a ,剩下的w都會xor上a
所以就變成了求解合法的a的數(shù)量,限制有n個不等式,形式為:
L[i] <= W[i] Xor a <= R[i]
你可能會覺得a會屬于[L[i] Xor W[i],R[i] Xor w[i]],但問題是原本[L,R]是連續(xù)的,但是異或w[i]后不一定連續(xù)。
出題很妙的地方:

我們利用[0,230-1]的線段樹,把[L[i],R[i]]分成O(logW)個連續(xù)的區(qū)間,且每個區(qū)間的形式是K…30位相同,0…k-1位是0到2k-1,這樣的區(qū)間異或上w[i]后仍然還是一個區(qū)間

剛才這一部分是官方題解里的,談談我的理解
剛才說了區(qū)間xor W[i]后不一定連續(xù),但是如果我們把區(qū)間[L[i],R[i]]分成好幾個小區(qū)間,這個小區(qū)間Xor W[i]后,這幾個小區(qū)間可能本身還是連續(xù)的(不看這幾個小區(qū)間之間的聯(lián)系,只看小區(qū)間本身)。
那該怎么分呢?我們利用[0,230-1]的線段樹,我們想下建樹過程,一開始是[L=0,R=111111…(一共30個1)],然后分治建邊,分成兩個區(qū)間[L=0,R=1111…(一共29個)],[L=1000…(一共29個0),R=11111…(一共30個1)],一直這樣下去,得到的區(qū)間都滿足下面形式:
[xxxx0000,xxxx1111],xxxx部分是相同的,也就是前k位相同,后k位分別是0和1
這樣的區(qū)間異或上一個數(shù)x后仍然還是一個連續(xù)完整區(qū)間(很神奇,可以自己測試以下)
我用L=80(101000),R=95(1011111),當x小于等于15(1111)時,[L,R]的區(qū)間還是本區(qū)間只是內部打亂順序,當大于15時[L,R]區(qū)間會整體變小,但是區(qū)間長度依舊不變。我認為是一位這個區(qū)間的對稱的,所以才會這樣
這樣就可以將原區(qū)間[L[i],R[i]]拆成n組區(qū)間,a屬于這個n組區(qū)間,那n組區(qū)間求個交(可以利用差分),就得到a的數(shù)量

代碼:

#include <iostream> #include <string> #include <cstring> #include <cmath> #include <algorithm> #include <queue> #include <iomanip> #include <map> #include <cstdio> #include <stack> #include <set> using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int ,int> pii; #define endl '\n' ll gcd(ll a, ll b){return b == 0 ? a : gcd(b, a % b); } void input(){freopen("in.txt", "r", stdin);freopen("out.txt", "w", stdout); } inline int read(){int x=0,f=1;char c=getchar();while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}while (c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();return x*f; } const int N = 1e6+10, M = N * 2, inf = 1e8; int n, L[N], R[N], W[N]; vector<pii> G[N]; vector<pii> seg, v; // l r 是當前點限制的左右取值范圍 // vl vr 是當前這段區(qū)間所代表的取值范圍 // dep 表示深度,v是在w1取0的條件下當前點的取值 void build(int l, int r, int vl, int vr, int dep, int v){if(l <= vl && vr <= r){int nowl = (vl ^ v) & (((1<<30)-1) ^ ((1<<dep) - 1));int nowr = nowl + (1<<dep) - 1;//cout<<"vl="<<vl<<" "<<"vr="<<vr<<endl;//cout<<"nowl="<<nowl<<" "<<"nowr="<<nowr<<endl; seg.push_back({nowl, nowr});}else{int mid = (vl + vr) >> 1;if(l <= mid) build(l, r, vl, mid, dep-1, v);if(r > mid) build(l, r, mid+1, vr, dep-1, v);} } // 使用dfs求解每個點的值 void dfs(int x, int fa, int val){if(x != 1) build(L[x], R[x], 0, (1<<30)-1, 30, val);for(auto i : G[x]){if(i.first == fa) continue;dfs(i.first, x, i.second^val);} } int main(){ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);cin>>n;for(int i = 1; i <= n; i++) cin>>L[i]>>R[i];for(int i = 1; i < n; i++){int u, v, w; cin>>u>>v>>w;G[u].push_back({v, w});G[v].push_back({u, w});}dfs(1, -1, 0);seg.push_back({L[1], R[1]});for(auto i : seg) v.push_back({i.first, 1}), v.push_back({i.second + 1, -1});//差分思想 sort(v.begin(), v.end());int res = 0, sum = 0;for(int i = 0; i < (int)v.size(); i++){sum += v[i].second;if(sum == n) //當存在n個區(qū)間同時滿足時,就是a的取值范圍 res += v[i+1].first - v[i].first;}cout<<res<<endl;return 0; }

總結

以上是生活随笔為你收集整理的Tree Xor(未完全搞定)的全部內容,希望文章能夠幫你解決所遇到的問題。

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