传送门
文章目录
- 题意:
- 思路:
题意:
给你一棵树,每个点原本都有一个权值wiw_iwi,但是你只知道相邻两个点之间的wu⊕wvw_u\oplus w_vwu⊕wv,问你有多少种w1,2,...,nw_{1,2,...,n}w1,2,...,n
n≤1e5,wi<230n\le1e5,w_i<2^{30}n≤1e5,wi<230
思路:
显然我们如果确定了一个点的权值,那么其他的点都就确定了。
更具体的是,我们可以求出111到其他点之间的w1⊕wxw_1\oplus w_xw1⊕wx,其中我们可以假设w1=0w_1=0w1=0,那么当给w1⊕aw_1\oplus aw1⊕a时,就相当于将其他w2,3,...,n⊕aw_{2,3,...,n}\oplus aw2,3,...,n⊕a,所以我们问题就转换成了对于每个区间求合法的aaa使得li≤wi⊕a≤ril_i\le w_i\oplus a\le r_ili≤wi⊕a≤ri,转换一下就是wi⊕[li,ri]w_i\oplus [l_i,r_i]wi⊕[li,ri]的合法区间。这个区间肯定不是连续的,所以考虑将其拆分成若干区间。
由于拆分的区间肯定不能很多,所以考虑用二进制来拆分这个区间。考虑这样一种形式的二进制区间[xxxx0000,xxxx1111][xxxx0000,xxxx1111][xxxx0000,xxxx1111],其中xxx表示可以是任意数,但是两个的xxx对应位置必须相同。这样的区间满足其异或上wiw_iwi仍是一段连续的区间。我们惊奇的发现,这个区间后半部分不正是线段树的每段区间吗?所以考虑建一棵[0,230−1][0,2^{30}-1][0,230−1]的线段树,将这个区间插入,可知最多能被分成lognlognlogn段区间。当这个区间被完全包含的时候,我们打一个懒标记即可。
查询的时候如果懒标记=n=n=n的时候,就直接返回区间长度即可。
// Problem: Tree Xor
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/11255/E
// Memory Limit: 524288 MB
// Time Limit: 4000 ms
//
// Powered by CP Editor (https://cpeditor.org)//#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
//#pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#include<random>
#include<cassert>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid ((tr[u].l+tr[u].r)>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std;//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); }
//void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); }
//void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;const int N=5000010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;int n,w[N],p[N];
int l[N],r[N],idx;
struct Node {int l,r;int cnt,lazy;
}tr[N<<2];
vector<PII>v[N];void dfs(int u,int fa) {for(auto x:v[u]) {if(x.X==fa) continue;w[x.X]=w[u]^x.Y;dfs(x.X,u);}
}int newnode() {int u=++idx;tr[u].l=tr[u].r=0;tr[u].cnt=tr[u].lazy=0;return u;
}void insert(int &u,int l,int r,int ql,int qr,int w,int dep) {if(!u) u=newnode();int nl=(l^w)&(((1<<30)-1)^((1<<(dep+1))-1));int nr=(l^w)|((1<<(dep+1))-1);if(nl>=ql&&nr<=qr) {tr[u].lazy++;tr[u].cnt++;return;}if(tr[u].cnt) {if(!tr[u].l) tr[u].l=newnode();if(!tr[u].r) tr[u].r=newnode();tr[tr[u].l].cnt+=tr[u].cnt; tr[tr[u].r].cnt+=tr[u].cnt;tr[u].cnt=0;}int mid=(l+r)>>1;int ll=(l^w)&(((1<<30)-1)^((1<<(dep))-1)),lr=(l^w)|((1<<(dep))-1);int rl=(r^w)&(((1<<30)-1)^((1<<(dep))-1)),rr=(r^w)|((1<<(dep))-1);if(w>>dep&1) {if(ql<=rr) insert(tr[u].r,mid+1,r,ql,qr,w,dep-1);if(qr>=ll) insert(tr[u].l,l,mid,ql,qr,w,dep-1);} else {if(ql<=lr) insert(tr[u].l,l,mid,ql,qr,w,dep-1);if(qr>=rl) insert(tr[u].r,mid+1,r,ql,qr,w,dep-1);}
}int query(int u,int l,int r) {if(!u) return 0;if(tr[u].cnt==n) return r-l+1;if(tr[u].cnt) {if(tr[u].l) tr[tr[u].l].cnt+=tr[u].cnt;if(tr[u].r) tr[tr[u].r].cnt+=tr[u].cnt;tr[u].cnt=0;}int ans=0,mid=(l+r)>>1;ans+=query(tr[u].l,l,mid);ans+=query(tr[u].r,mid+1,r);return ans;
}int main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);scanf("%d",&n);for(int i=1;i<=n;i++) scanf("%d%d",&l[i],&r[i]);for(int i=1;i<=n-1;i++) {int a,b,c; scanf("%d%d%d",&a,&b,&c);v[a].pb({b,c}); v[b].pb({a,c});}dfs(1,0); int rt=newnode();int limit=(1<<30)-1;for(int i=1;i<=n;i++) {insert(rt,0,limit,l[i],r[i],w[i],29);}printf("%d\n",query(1,0,limit));return 0;
}
/**/