E-Tree Xor

首先不考虑区间限制条件,我们给定其中一个点的权值后,那么其他点的权值也就确定。比如 val1=0\text{val}_1=0val1​=0,即可通过变得限制求出其他点valu\text{val}_uvalu​,而且不难发现如果val1=0⊕a\text{val}_1=0\oplus aval1​=0⊕a那么其余点的权值valu=0⊕a\text{val}_u=0\oplus avalu​=0⊕a

下面记valu\text{val}_uvalu​为当val1=0\text{val}_1=0val1​=0时,u点的权值。

于是问题转化为求出满足下面区间限制aaa的个数。
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​⊕a≤R1​L2​≤val2​⊕a≤R2​…Ln​≤valn​⊕a≤Rn​

考虑其中一种限制直观的想法是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​⊕a≤Ru​⇒L1​⊕val1​ ≤a≤R1​⊕val1​不难发现上面转化是错误的,而且可以发现aaa的区间是不连续的!!!需要找出这些不连续的区间!

于是就很难处理,后面就是讲题人的做法(真滴强)


我们可以利用 [0,230−1][0,2^{30}-1][0,230−1] 的线段树, 把 [Li,Ri][L_i , R_i][Li​,Ri​] 分成 log⁡W\log WlogW个连续的区间, 且每个区间的形式是 : [∗∗∗00…00,∗∗∗11…11][***00\dots00,***11\dots 11][∗∗∗00…00,∗∗∗11…11], 这样的区间异或上 vali\text{val}_ivali​ 后仍然还是一个区间

不妨设∗∗∗***∗∗∗的数量是k

不难发现区间[∗∗∗00…00,∗∗∗11…11][***00\dots00,***11\dots 11][∗∗∗00…00,∗∗∗11…11]抑或上vali\text{val}_ivali​的区间是[−−−00…00,−−−,11…11][- - -00\dots00,---,11\dots11][−−−00…00,−−−,11…11]
其中−−−---−−−是(∗∗∗00…00)⊕vali(***00\dots00)\oplus \text{val}_i(∗∗∗00…00)⊕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}\Rightarrow⊕10011010⇒ [00110000,00111111][\color{Blue}{0011} \color{Red}{0000},\color{Blue}{0011} \color{Red}{1111}][00110000,00111111]

蓝色部分异或0011=1010⊕0011\color{Blue}0011=1010\oplus00110011=1010⊕0011原红色部分不变,稍微思考一下就知道为什么了。

通过上面操作成功找出这些不连续的区间!!!


然后就sort区间差分乱搞就行。时间复杂度2log,可以用线段树维护所有不合法区间的并集,把不合法的区间标记为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)));//异或之后的区间[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​⊕a≤R1​L2​≤val2​⊕a≤R2​…Ln​≤valn​⊕a≤Rn​
转化成
[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​⊕a≤R1​]➖[val1​⊕a<L1​][val2​⊕a≤R2​]➖[val2​⊕a<L2​]…[valn​⊕a≤Rn​]➖[valn​⊕a<Ln​]
上面的➖理解为两个集合相减。

实际上我需要求的就是⊕a≤b\oplus a\leq b⊕a≤b的区间,显然字典树可以做,相当于求⊕a≤b\oplus a\leq b⊕a≤b的数有哪些,和第二次杭电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树)相关推荐

  1. 2021牛客暑期多校训练营4 E - Tree Xor 线段树 + 拆分区间

    传送门 文章目录 题意: 思路: 题意: 给你一棵树,每个点原本都有一个权值wiw_iwi​,但是你只知道相邻两个点之间的wu⊕wvw_u\oplus w_vwu​⊕wv​,问你有多少种w1,2,.. ...

  2. 2021牛客暑期多校训练营3 B Black and white 最小生成树 + 思维

    传送门 文章目录 题意: 思路: 题意: 思路: 对于每个数的位置(i,j)(i,j)(i,j),如果将这个位置染黑,那么我们连一个i−>j+ni->j+ni−>j+n的边,可以发现 ...

  3. 2021牛客暑期多校训练营1 G Game of Swapping Numbers 思维 + 巧妙的转换

    传送门 文章目录 题意: 思路: 题意: 给你两个数组A,BA,BA,B,你可以选择AAA的两个位置i,j,i<ji,j,i<ji,j,i<j交换Ai,AjA_i,A_jAi​,Aj ...

  4. 2021牛客暑期多校训练营4 D-Rebuild Tree(prufer序列+树形dp)

    D-Rebuild Tree Prufer 是这样建立的:每次选择一个编号最小的叶结点并删掉它,然后在序列中记录下它连接到的那个结点.重复n−2n-2n−2次后就只剩下两个结点,算法结束.(为什么不是 ...

  5. 【2021牛客暑期多校训练营4】Average (二分答案,区间/子数组最大平均值,)

    J Average 题意: 给出长为n,m的序列ai和bi,定义nm的矩阵wij=ai+bj,求一个大小>=xy的子矩阵的平均值最大. 思路: 因为n的范围为1e5,直接n*m计算出wij就已经 ...

  6. 【2021牛客暑期多校训练营9】E Eyjafjalla (倍增,dfs序,主席树)

    E Eyjafjalla 题意: 题意:给定一个以1为根的有根树,孩子的点权小于父亲的点权. 多次询问,每次询问包含x节点的权值范围为[l, r] 的极大连通块的大小. 思路: 病毒传播可以看作两个阶 ...

  7. 2021牛客暑期多校训练营9

    2021牛客暑期多校训练营9 题号 题目 知识点 A A Math Challenge B Best Subgraph C Cells D Divide-and-conquer on Tree E E ...

  8. 2021牛客暑期多校训练营5

    2021牛客暑期多校训练营5 题号 题目 知识点 A Away from College B Boxes 概率 C Cheating and Stealing D Double Strings 线性d ...

  9. 2021牛客暑期多校训练营4

    2021牛客暑期多校训练营4 题号 题目 知识点 A Course B Sample Game C LCS D Rebuild Tree E Tree Xor 思维+线段树 F Just a joke ...

  10. 2021牛客暑期多校训练营3

    2021牛客暑期多校训练营3 题号 题目 知识点 A Guess and lies B Black and white C Minimum grid 二分图匹配 D Count E Math 数论+打 ...

最新文章

  1. 附录:PyTorch记事本
  2. thinkpad密码忘记
  3. Delphi通过ICMP检测与远程主机连接
  4. 云服务器拷贝文件大小,如何从云服务器上拷贝大文件
  5. 操作系统—死锁的预防
  6. 【鱼眼镜头8】张正友畸变公式;鱼眼的畸变公式需要使用入射角
  7. Python 爬虫--下载音乐
  8. 20000条笑话保证笑死你
  9. CSS-Learning | 使用border-radius创建圆形和胶囊形状(长圆形)
  10. 常见互联网34个术语解释
  11. CUDA C/C++ 从入门到入土 第一步——让你的CUDA跑起来
  12. SpringBoot教程(十一)——将Bean放入Spring容器中的五种方式
  13. windows桌面图标显示不正常
  14. python爬取疫情数据并存入excel中(包括国内各省份,全球,国内外历史疫情数据)代码可以直接运行
  15. 2021-05-28 aps助油田服务与设备行业实现数字化
  16. 鼓励参与期货市场套期保值
  17. Python识别验证码----数美图标点选
  18. 云网站,云平台、云服务器、云数据库网站大全
  19. linux 字符串比较、数值比较
  20. 新员工转正申请书如何写呢?工作转正申请书范文分享

热门文章

  1. 学计算机与学英语作文,初二英语作文(关于计算机与学习)
  2. etcd php,etcd集群备份和数据恢复
  3. robcad和catia是什么关系_proe/CATIA/UG/SolidWorks软件区别与联系
  4. ajax php 动态,jQuery+PHP+Ajax实现动态数字统计展示功能
  5. java实用教程——组件及事件处理——对话框(消息对话框,输入对话框,确认对话框)
  6. 电子工程系庆贺电贺信_创造下一代光电子集成电路
  7. leetcode968. 监控二叉树
  8. [汇编语言]常用命令
  9. ajax获取php的数组,使用AJAX请求获取数组并将其传递到php数组中 - javascript
  10. 数据结构与算法--位运算