2021牛客暑期多校训练营4 E-Tree Xor(异或+思维+区间交 or Trie树)

E-Tree Xor

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

下面记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 L1val1aR1L2val2aR2LnvalnaRn

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

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


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

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

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

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

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


然后就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 L1val1aR1L2val2aR2LnvalnaRn
转化成
[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] [val1aR1][val1a<L1][val2aR2][val2a<L2][valnaRn][valna<Ln]
上面的➖理解为两个集合相减。

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

要加油哦~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/318770.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【.NET Core项目实战-统一认证平台】第八章 授权篇-IdentityServer4源码分析

上篇文章我介绍了如何在网关上实现客户端自定义限流功能&#xff0c;基本完成了关于网关的一些自定义扩展需求&#xff0c;后面几篇将介绍基于IdentityServer4&#xff08;后面简称Ids4&#xff09;的认证相关知识&#xff0c;在具体介绍ids4实现我们统一认证的相关功能前&…

[科技]Loj#6564-最长公共子序列【bitset】

正题 题目链接:https://loj.ac/p/6564 题目大意 给两个序列a,ba,ba,b求它们的最长公共子序列。 1≤n,m,ai,bi≤71041\leq n,m,a_i,b_i\leq 7\times 10^41≤n,m,ai​,bi​≤7104 解题思路 无意间看到的一个bitsetbitsetbitset科技。 首先设fi,jf_{i,j}fi,j​表示aaa串匹配到…

牛客题霸 [找到字符串的最长无重复字符子串] C++题解/答案

牛客题霸 [找到字符串的最长无重复字符子串] C题解/答案 题目描述 给定一个数组arr&#xff0c;返回arr的最长无的重复子串的长度(无重复指的是所有数字都不相同)。 题解&#xff1a; i和j两个指针分别指不重复子串的两端&#xff0c;根据情况各自移动&#xff0c;记录最大…

并查集:P1196 [NOI2002] 银河英雄传说

传送门 带权并查集最棒了 dep记录深度&#xff0c;size记录集合大小 转移见代码 #include<cstdio> #include<algorithm> #include<iostream> using namespace std; const int N31000; int n,m; int t; int dep[N],fa[N],size[N]; char s; int a,b; int find…

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

D-Rebuild Tree Prufer 是这样建立的&#xff1a;每次选择一个编号最小的叶结点并删掉它&#xff0c;然后在序列中记录下它连接到的那个结点。重复n−2n-2n−2次后就只剩下两个结点&#xff0c;算法结束。&#xff08;为什么不是n−1n-1n−1次呢&#xff1f;因为第n−1n-1n−1…

牛客题霸 [ 求二叉树的层序遍历] C++题解/答案

牛客题霸 [ 求二叉树的层序遍历] C题解/答案 题目描述 给定一个二叉树&#xff0c;返回该二叉树层序遍历的结果&#xff0c;&#xff08;从左到右&#xff0c;一层一层地遍历&#xff09; 例如&#xff1a; 给定的二叉树是{3,9,20,#,#,15,7}, 该二叉树层序遍历的结果是 [ [3…

T183637-变异距离(2021 CoE III C)【单调栈】

正题 题目链接:https://www.luogu.com.cn/problem/T183637 题目大意 给出nnn个二元组(xi,yi)(x_i,y_i)(xi​,yi​)&#xff0c;求最大的 ∣xi−xj∣min{∣yi∣,∣yj∣}|x_i-x_j|\times min\{|y_i|,|y_j|\}∣xi​−xj​∣min{∣yi​∣,∣yj​∣} 1≤n≤2106,−106≤xi≤106,−…

dfs剪枝:洛谷P2809 hzwer爱折纸

传送门 解析 dfs暴力枚举即可 这题的重点是如何剪枝 不难发现&#xff0c;随着不断处理&#xff0c;纸条只会越来越短&#xff0c;且所有数字总加和不变 我一开始想到了2个条件&#xff1a; 1.当前长度比理想纸条小&#xff0c;return&#xff1b; 2.总加和与理想纸条不等&a…

2021牛客暑期多校训练营2 B-Cannon(组合+推式子)

B-Cannon 首先nnn个炮在一行操作一次的方案数为2(n−2)2(n-2)2(n−2):前面两个炮只能向右吃&#xff0c;最后两个跑只能向左吃&#xff0c;而其余的炮既可以向左也可以向右&#xff0c;于是有42(n−4)42(n-4)42(n−4)种 于是操作mmm次的操作排列的方案数为2m(n−2)(n−3)...(…

[译]聊聊C#中的泛型的使用

写在前面今天忙里偷闲在浏览外文的时候看到一篇讲C#中泛型的使用的文章&#xff0c;因此加上本人的理解以及四级没过的英语水平斗胆给大伙进行了翻译&#xff0c;当然在翻译的过程中发现了一些问题&#xff0c;因此也进行了纠正&#xff0c;当然&#xff0c;原文的地址我放在最…

牛客题霸 [ 最长递增子序列] C++题解/答案

牛客题霸 [ 最长递增子序列] C题解/答案 题目描述 给定数组arr&#xff0c;设长度为n&#xff0c;输出arr的最长递增子序列。&#xff08;如果有多个答案&#xff0c;请输出其中字典序最小的&#xff09; 题意&#xff1a; 直接暴力会超时 应该用二分贪心 题解&#xff1a…

P5405-[CTS2019]氪金手游【树形dp,容斥,数学期望】

前言 话说在LojLojLoj下了个数据发现这题的名字叫fgofgofgo 正题 题目链接:https://www.luogu.com.cn/problem/P5405 题目大意 nnn张卡的权值为1/2/31/2/31/2/3的概率权重分别是px,1/2/3p_{x,1/2/3}px,1/2/3​&#xff0c;然后按照权值每次获得一张未获得的卡&#xff0c;然后…

模板:线段树

文章目录引言思想模板建树单点修改 / 查询区间修改/查询总结练习引言 有一类题目:要求在区间上维护信息&#xff0c;比如带修改区间求和问题。考虑到枚举求和肯定会超时&#xff0c;我们可以通过一些数据结构来维护信息&#xff0c;例如线段树。 它功能强大&#xff0c;支持区…

Docker最全教程——从理论到实战(三)

容器是应用走向云端之后必然的发展趋势&#xff0c;因此笔者非常乐于和大家分享我们这段时间对容器的理解、心得和实践。本篇教程持续编写了2个星期左右&#xff0c;只是为了大家更好地了解、理解和消化这个技术&#xff0c;能够搭上这波车。你可以关注我们的公众号“magiccode…

2021牛客暑期多校训练营4 H-Convolution(数学)

H-Convolution x⨂yxygcd⁡(x,y)x\bigotimes y\frac{xy}{\gcd(x,y)}x⨂ygcd(x,y)xy​ 下面大佬题解推&#x1f981; Ultraman-Ace题解 #include<bits/stdc.h> using namespace std; using lllong long; template <class Tint> T rd() {T res0;T fg1;char chgetcha…

牛客题霸 [ 排序] C++题解/答案

题目描述 给定一个数组&#xff0c;请你编写一个函数&#xff0c;返回该数组排序后的形式。 题意&#xff1a; 排序的方式有很多 二分呀&#xff0c;桶排呀归并等等 stl里的sort快速排序方便好用 题解&#xff1a; class Solution { public:/*** 代码中的类名、方法名、参…

ARC106E-Medals【hall定理,高维前缀和】

正题 题目链接:https://atcoder.jp/contests/arc106/tasks/arc106_e 题目大意 nnn个员工&#xff0c;第iii个在[1,Ai][1,A_i][1,Ai​]工作&#xff0c;[Ai1,2Ai][A_i1,2\times A_{i}][Ai​1,2Ai​]休息&#xff0c;[2Ai1,3Ai][2\times A_i1,3\times A_i][2Ai​1,3Ai​]工作…以…

高并发、低延迟之C#玩转CPU高速缓存(附示例)

写在前面好久没有写博客了&#xff0c;一直在不断地探索响应式DDD&#xff0c;又get到了很多新知识&#xff0c;解惑了很多老问题&#xff0c;最近读了Martin Fowler大师一篇非常精彩的博客The LMAX Architecture&#xff0c;里面有一个术语Mechanical Sympathy&#xff0c;姑且…

RMQ问题:与众不同(st表的高端应用)

解析 预处理 用pre[i]表示以i结尾的最长完美序列起始点&#xff0c;用last[i]表示数字i最后出现的位置 那么可以得到递推式&#xff1a; pre[i]max(pre[i-1],last[x[i]]1);也就是说这个pre要么是受前一位一样的限制&#xff0c;要么是受自己的限制 用f[i]表示以i结尾的最长完…

codeforces1554 E. You(思维+数学+转化)

E. You 首先我们假设每个节点有个点权&#xff0c;点权是儿子的数量。 一个点可以和他的父亲所要权值1&#xff08;先删去自己&#xff0c;再删去父亲&#xff09;&#xff0c;并且此操作不可逆。于是dfs从叶子节点一次递推即可得出某个kkk是否能作为gcd⁡\gcdgcd。 由于上述…