2021牛客暑期多校训练营4 E.Tree Xor(区间异或+扫描线)
Posted issue是fw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021牛客暑期多校训练营4 E.Tree Xor(区间异或+扫描线)相关的知识,希望对你有一定的参考价值。
先 d f s dfs dfs一遍求出 r r r数组使得 w [ i ] = z [ i ] ⊕ w [ 1 ] w[i]=z[i]\\oplus w[1] w[i]=z[i]⊕w[1]
于是现在就是找到 x x x解的数量,对于 i ∈ [ 1 , n ] i\\in[1,n] i∈[1,n]都有 x ⊕ z i ∈ [ l i , r i ] x\\oplus z_i\\in[l_i,r_i] x⊕zi∈[li,ri]
那么对于每个点 i i i都有一个合法 x x x的集合,对于每个点求一遍然后求交即可
可以把 [ l i , r i ] [l_i,r_i] [li,ri]拆为若干个区间,这些区间的前缀固定,左端点的后缀是 00000... 00000... 00000...,右端点的后缀是 11111.... 11111.... 11111....
然后 z i z_i zi与这种区间异或,之后得到的还是一个连续的区间
于是就把区间 [ l i , r i ] [l_i,r_i] [li,ri]放在值域为 [ 0 , 2 31 − 1 ] [0,2^{31}-1] [0,231−1]的线段树上去就可以跑出对应的区间
最后对这 n n n个限制得到的区间求交集,做一遍扫描线即可
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define int long long
#define mid (l+r>>1)
#define lson l,mid
#define rson mid+1,r
typedef pair<int,int>p;
const int maxn = 3e5+10;
vector<p >sw,vec[maxn];
int n,l[maxn],r[maxn],z[maxn];
bool com(p a,p b){ return a.fi<b.fi || ( a.fi==b.fi && a.se>b.se); }
void dfs(int u,int fa)
{
for(auto v:vec[u] )
{
if( v.fi==fa ) continue;
z[v.fi] = z[u]^v.se;
dfs( v.fi,u );
}
}
void fz(int l,int r,int L,int R,int val,int dep)
{
if( l>R || r<L ) return;
if( l>=L && r<=R )
{
int prefix = l^val,x = (1<<dep)-1;
prefix -= ( val&x );
sw.push_back( {prefix,1} );
sw.push_back( {prefix+(r-l)+1,-1 } );
return;
}
fz( lson,L,R,val,dep-1 ); fz( rson,L,R,val,dep-1 );
}
signed main()
{
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;
vec[u].push_back( {v,w} ); vec[v].push_back( {u,w} );
}
dfs( 1,1 );
int mx = (1<<30)-1;
for(int i=1;i<=n;i++) fz( 0,mx,l[i],r[i],z[i],30 );
sort( sw.begin(),sw.end(),com );
int ans = 0, las = -1, now = 0;
for( auto v:sw )
{
if( now==n && v.se==-1 ) ans += v.fi-las, las = -1;
now += v.se;
if( now==n && las==-1 ) las = v.fi;
}
cout << ans;
return 0;
}
以上是关于2021牛客暑期多校训练营4 E.Tree Xor(区间异或+扫描线)的主要内容,如果未能解决你的问题,请参考以下文章
2021牛客暑期多校训练营4 Tree Xor (区间异或上一个数+区间求交)