题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=5361

好神的一道题啊!

容易看出来是要用维护权值的数据结构,因此树链剖分首先pass掉。

那么不妨用树上主席树试试?每个版本存当前点到根路径上的点的权值。

如果维护区间权值数量的话,你发现没有明确的判断条件来明确每一次主席树上二分是走左子树还是右子树。

这时就要用到一个套路了:将1~200000的所有权值随机映射成unsigned long long的数,主席树维护区间权值异或和。

再维护前缀权值异或和,这样每次在主席树上二分时只要判断左子树的权值异或和是否等于左子树代表的区间的权值异或和。

如果等于,就说明左子树所有权值都出现了奇数次,答案一定在右子树中。反之则在左子树中。

因为是随机化算法,所以只能保证大概率的正确性,不过这种套路在做题时也可以适当借鉴。

最后注意主席树区间要开到200001,因为可能前200000个数都有,答案是200001。

#include<set>
#include<map>
#include<stack>
#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ull unsigned long long
using namespace std;
inline char _read()
{
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
int x=0,f=1;char ch=_read();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=_read();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=_read();}
return x*f;
}
int T;
int x,y;
int n,m;
int cnt;
int tot;
int a[200010];
int d[200010];
ull v[200010];
int to[400010];
int ls[8000010];
int rs[8000010];
ull num[200010];
int root[200010];
int head[200010];
int next[400010];
ull sum[8000010];
int f[200010][19];
ull Rand()
{
return ((ull)rand()<<45)|((ull)rand()<<30)|(rand()<<15)|rand();
}
void add(int x,int y)
{
tot++;
next[tot]=head[x];
head[x]=tot;
to[tot]=y;
}
void updata(int &rt,int pre,int l,int r,int k)
{
rt=++cnt;
if(l==r)
{
sum[rt]=sum[pre]^v[l];
return ;
}
ls[rt]=ls[pre];
rs[rt]=rs[pre];
int mid=(l+r)>>1;
if(k<=mid)
{
updata(ls[rt],ls[pre],l,mid,k);
}
else
{
updata(rs[rt],rs[pre],mid+1,r,k);
}
sum[rt]=sum[ls[rt]]^sum[rs[rt]];
}
void dfs(int x)
{
d[x]=d[f[x][0]]+1;
updata(root[x],root[f[x][0]],1,200001,a[x]);
for(int i=1;i<=18;i++)
{
f[x][i]=f[f[x][i-1]][i-1];
}
for(int i=head[x];i;i=next[i])
{
if(to[i]!=f[x][0])
{
f[to[i]][0]=x;
dfs(to[i]);
}
}
}
int lca(int x,int y)
{
if(d[x]<d[y])
{
swap(x,y);
}
int dep=d[x]-d[y];
for(int i=0;i<=18;i++)
{
if((dep&(1<<i))!=0)
{
x=f[x][i];
}
}
if(x==y)
{
return x;
}
for(int i=18;i>=0;i--)
{
if(f[x][i]!=f[y][i])
{
x=f[x][i];
y=f[y][i];
}
}
return f[x][0];
}
int query(int x,int y,int fa,int anc,int l,int r)
{
if(l==r)
{
return l;
}
ull res=sum[ls[x]]^sum[ls[y]]^sum[ls[fa]]^sum[ls[anc]];
int mid=(l+r)>>1;
if(res==(num[mid]^num[l-1]))
{
return query(rs[x],rs[y],rs[fa],rs[anc],mid+1,r);
}
else
{
return query(ls[x],ls[y],ls[fa],ls[anc],l,mid);
}
}
int main()
{
srand(20020419);
T=read();
for(int i=1;i<=200001;i++)
{
v[i]=Rand();
num[i]=num[i-1]^v[i];
}
while(T--)
{
cnt=0;
tot=0;
memset(d,0,sizeof(d));
memset(f,0,sizeof(f));
memset(ls,0,sizeof(ls));
memset(rs,0,sizeof(rs));
memset(sum,0,sizeof(sum));
memset(root,0,sizeof(root));
memset(head,0,sizeof(head));
n=read();
m=read();
for(int i=1;i<=n;i++)
{
a[i]=read();
}
for(int i=1;i<n;i++)
{
x=read();
y=read();
add(x,y);
add(y,x);
}
dfs(1);
while(m--)
{
x=read();
y=read();
int anc=lca(x,y);
printf("%d\n",query(root[x],root[y],root[anc],root[f[anc][0]],1,200001));
}
}
}

BZOJ5361[Lydsy1805月赛]对称数——主席树+随机化的更多相关文章

  1. 【主席树上二分】bzoj5361: [Lydsy1805月赛]对称数

    随机化选讲例题 题目大意 小 Q 认为,偶数具有对称美,而奇数则没有.给定一棵 n 个点的树,任意两点之间有且仅有一条直接或间接路径.这些点编号依次为 1 到 n,其中编号为 i 的点上有一个正整数 ...

  2. [BZOJ5361][Lydsy1805月赛]对称数

    bzoj Description 给你一棵树,每个点有一个编号\(a_i\).\(Q\)组询问,每次问一条路径上最小的出现了偶数次的编号是多少(包括零次). 多组数据,\(T\le10,n,Q,a_i ...

  3. [Lydsy1805月赛]对称数 BZOJ5361

    分析: 这个题,还是蛮有趣的.考虑,如果l,r区间内的所有数出现奇数次,那么[l-1,r]的抑或和等于所得抑或和. 之后怎么维护呢,主席树维护区间抑或和,记得将每个点附上一个ull级别的随机数,之后抑 ...

  4. [Lydsy1805月赛] 对称数

    挺不错的一道数据结构题QWQ. 一开始发现这个题如果不看数据范围的话,妥妥的树上莫队啊23333,然鹅10组数据是不可能让你舒舒服服的树上莫队卡过的23333 于是想了想,这个题的模型就是,把u到v链 ...

  5. BZOJ 4408: [Fjoi 2016]神秘数 [主席树]

    传送门 题意: 一个可重复数字集合S的神秘数定义为最小的不能被S的子集的和表示的正整数.例如S={1,1,1,4,13},8无法表示为集合S的子集的和,故集合S的神秘数为8.现给定n个正整数a[1]. ...

  6. BZOJ4408&4299[Fjoi 2016]神秘数——主席树

    题目描述 一个可重复数字集合S的神秘数定义为最小的不能被S的子集的和表示的正整数.例如S={1,1,1,4,13},1 = 1 2 = 1+1 3 = 1+1+1 4 = 4 5 = 4+1 6 = ...

  7. 【bzoj4408】[Fjoi 2016]神秘数 主席树

    题目描述 一个可重复数字集合S的神秘数定义为最小的不能被S的子集的和表示的正整数.例如S={1,1,1,4,13},1 = 12 = 1+13 = 1+1+14 = 45 = 4+16 = 4+1+1 ...

  8. P4587 [FJOI2016]神秘数(主席树)

    题意:给出1e5个数 查询l,r区间内第一个不能被表示的数 比如1,2,4可以用子集的和表示出[1,7] 所以第一个不能被表示的是8 题解:先考虑暴力的做法 把这个区间内的数字按从小到大排序后 从前往 ...

  9. COGS 930. [河南省队2012] 找第k小的数 主席树

    主席树裸板子 #include<cstdio> #include<iostream> #include<algorithm> #define MAXN 100005 ...

随机推荐

  1. 分布式理论——quorum原理

    编者按:本篇文章是网上一些文章的合集,并不是原创,谢谢各位的分享. 一.基于Quorum投票的冗余控制算法 Quorom 机制,是一种分布式系统中常用的,用来保证数据冗余和最终一致性的投票算法,其主要 ...

  2. 【LGR-049】洛谷7月月赛

    Preface Luogu八月月赛都结束了我才来补七月月赛 这次月赛还是很狗的,在绍一的晚上恰逢刮台风,然后直接打到一半断网了 结果都没有交上去GG 感觉这次难度适中,解法也比较清新自然吧,十分给个九 ...

  3. C#_委托的使用

    C#基础---委托的使用   一:什么是委托     委托是一种定义方法签名的类型当实例化委托时,您可以将其实例与任何具有兼容签名的方法相关联.您可以通过委托实例调用方法.委托是一个引用类型,所以它具 ...

  4. Docker管理工具 - Swarm部署记录

    之前介绍了Docker集群管理工具-Kubernetes部署记录,下面介绍另一个管理工具Swarm的用法,Swarm是Docker原生的集群管理软件,与Kubernetes比起来比较简单. Swarm ...

  5. zabbix邮件报警功能的验证

    zabbix里面设置了很多监控项,有很多重要的监控预警,必须保证zabbix邮件报警功能正常,以确保那些告警信息能及时发送到运维人员的邮箱里. 所以需要每天8:30发一封确认zabbix邮件报警功能正 ...

  6. Nginx+keepalived 双机热备(主主模式)

    之前已经介绍了Nginx+Keepalived双机热备的主从模式,今天在此基础上说下主主模式的配置. 由之前的配置信息可知:master机器(master-node):103.110.98.14/19 ...

  7. iOS APP 中H5视频默认全屏播放问题解决

    问题描述:在Android中,视频可以正常在H5页面局部播放,iOS中则自动切换至全屏模式. 查看资料得以解决,20190301记录下来. 解决方法:IOS10及以后,在 video标签页中只包含 w ...

  8. 全景3d

    Three.js Tour.js Run.js 3D Css3 酷家乐:https://www.kujiale.com/ 爱空间:http://bj.ikongjian.com/?utm_source ...

  9. Pair_Work Project

    结对项目小记 ——by    12061227 康    12061179 宇帆 结对编程就是一种敏捷软件开发的方法,两个人在一个计算机上共同工作.一个人输入,而另一个人检查他输入的每一行代码.输入代 ...

  10. Linux内核分析 读书笔记 (第七章)

    第七章 链接 1.链接是将各种代码和数据部分收集起来并组合成为一个单一文件的过程,这个文件可被加载(或被拷贝)到存储器并执行. 2.链接可以执行于编译时,也就是在源代码被翻译成机器代码时:也可以执行于 ...