Tree Xor(未完全搞定)
Posted Jozky86
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Tree Xor(未完全搞定)相关的知识,希望对你有一定的参考价值。
题意:
一颗有n个点的树,边权给出,第i个节点的权值为Wi,但并不知道Wi,只知道Wi在[Li,Ri],边权等于两端点的异或值
问W序列有多少可能
题解:
如果我们知道一个点的值,就可以推出其他所有点的值。
现在我们令w[1]=0,解出剩下的w,如果令w[1] = a ,剩下的w都会xor上a
所以就变成了求解合法的a的数量,限制有n个不等式,形式为:
L[i] <= W[i] Xor a <= R[i]
你可能会觉得a会属于[L[i] Xor W[i],R[i] Xor w[i]],但问题是原本[L,R]是连续的,但是异或w[i]后不一定连续。
出题很妙的地方:
我们利用[0,230-1]的线段树,把[L[i],R[i]]分成O(logW)个连续的区间,且每个区间的形式是K…30位相同,0…k-1位是0到2k-1,这样的区间异或上w[i]后仍然还是一个区间
刚才这一部分是官方题解里的,谈谈我的理解
刚才说了区间xor W[i]后不一定连续,但是如果我们把区间[L[i],R[i]]分成好几个小区间,这个小区间Xor W[i]后,这几个小区间可能本身还是连续的(不看这几个小区间之间的联系,只看小区间本身)。
那该怎么分呢?我们利用[0,230-1]的线段树,我们想下建树过程,一开始是[L=0,R=111111…(一共30个1)],然后分治建边,分成两个区间[L=0,R=1111…(一共29个)],[L=1000…(一共29个0),R=11111…(一共30个1)],一直这样下去,得到的区间都满足下面形式:
[xxxx0000,xxxx1111],xxxx部分是相同的,也就是前k位相同,后k位分别是0和1
这样的区间异或上一个数x后仍然还是一个连续完整区间(很神奇,可以自己测试以下)
我用L=80(101000),R=95(1011111),当x小于等于15(1111)时,[L,R]的区间还是本区间只是内部打乱顺序,当大于15时[L,R]区间会整体变小,但是区间长度依旧不变。我认为是一位这个区间的对称的,所以才会这样
这样就可以将原区间[L[i],R[i]]拆成n组区间,a属于这个n组区间,那n组区间求个交(可以利用差分),就得到a的数量
代码:
#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 是当前这段区间所代表的取值范围
// 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个区间同时满足时,就是a的取值范围
res += v[i+1].first - v[i].first;
}
cout<<res<<endl;
return 0;
}
以上是关于Tree Xor(未完全搞定)的主要内容,如果未能解决你的问题,请参考以下文章