BZOJ5361[Lydsy1805月赛]对称数——主席树+随机化
题目链接: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月赛]对称数——主席树+随机化的更多相关文章
- 【主席树上二分】bzoj5361: [Lydsy1805月赛]对称数
		
随机化选讲例题 题目大意 小 Q 认为,偶数具有对称美,而奇数则没有.给定一棵 n 个点的树,任意两点之间有且仅有一条直接或间接路径.这些点编号依次为 1 到 n,其中编号为 i 的点上有一个正整数 ...
 - [BZOJ5361][Lydsy1805月赛]对称数
		
bzoj Description 给你一棵树,每个点有一个编号\(a_i\).\(Q\)组询问,每次问一条路径上最小的出现了偶数次的编号是多少(包括零次). 多组数据,\(T\le10,n,Q,a_i ...
 - [Lydsy1805月赛]对称数 BZOJ5361
		
分析: 这个题,还是蛮有趣的.考虑,如果l,r区间内的所有数出现奇数次,那么[l-1,r]的抑或和等于所得抑或和. 之后怎么维护呢,主席树维护区间抑或和,记得将每个点附上一个ull级别的随机数,之后抑 ...
 - [Lydsy1805月赛]  对称数
		
挺不错的一道数据结构题QWQ. 一开始发现这个题如果不看数据范围的话,妥妥的树上莫队啊23333,然鹅10组数据是不可能让你舒舒服服的树上莫队卡过的23333 于是想了想,这个题的模型就是,把u到v链 ...
 - BZOJ 4408: [Fjoi 2016]神秘数 [主席树]
		
传送门 题意: 一个可重复数字集合S的神秘数定义为最小的不能被S的子集的和表示的正整数.例如S={1,1,1,4,13},8无法表示为集合S的子集的和,故集合S的神秘数为8.现给定n个正整数a[1]. ...
 - 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 = ...
 - 【bzoj4408】[Fjoi 2016]神秘数  主席树
		
题目描述 一个可重复数字集合S的神秘数定义为最小的不能被S的子集的和表示的正整数.例如S={1,1,1,4,13},1 = 12 = 1+13 = 1+1+14 = 45 = 4+16 = 4+1+1 ...
 - P4587 [FJOI2016]神秘数(主席树)
		
题意:给出1e5个数 查询l,r区间内第一个不能被表示的数 比如1,2,4可以用子集的和表示出[1,7] 所以第一个不能被表示的是8 题解:先考虑暴力的做法 把这个区间内的数字按从小到大排序后 从前往 ...
 - COGS 930. [河南省队2012] 找第k小的数 主席树
		
主席树裸板子 #include<cstdio> #include<iostream> #include<algorithm> #define MAXN 100005 ...
 
随机推荐
- ubuntu 解决TXT文本的乱码的问题。
			
windows 系统上编辑的 txt 文本,在ubuntu上出现 乱码,我是这样解决的 1.terminal上输入以下命令: gsettings set org.gnome.gedit.prefere ...
 - 九,ESP8266 判断是断电上电(强制硬件复位)之后运行的内部程序还是内部软件复位之后运行的程序(基于Lua脚本语言)
			
现在我有一个需求,WIFI模块控制一个继电器,我要做的是如果内部程序跑乱了,造成了内部程序复位重启,那么控制继电器的状态不能改变 如果是设备断电了,然后又来电了,我需要的是继电器一定要是断开才好.不能 ...
 - oracle 相除后保留指定位数小数round()
			
) xxx from dual; XXX---------- 3.8871
 - java算法----排序----(1)插入排序
			
package log; public class Test4 { /** * java算法---插入排序 * * @param args */ public static void main(Str ...
 - 基于tensorflow的躲避障碍物的ai训练
			
import pygameimport randomfrom pygame.locals import *import numpy as npfrom collections import deque ...
 - sqlserver 发送http请求
			
sp_configure 'show advanced options', 1; GO RECONFIGURE; GO sp_configure 'Ole Automation Procedures' ...
 - [C#]使用Windows Form开发的天气预报小工具
			
用C#编写的天气预报小工具 功能 1.查询中国省份.城市及地区三级的天气预报: 2.显示1-7天一周的天气预报及未来8-15天的天气预报: 3.能定制地区的天气预报. 界面 源代码: https:// ...
 - SpringBoot日记——ElasticSearch全文检索
			
看到标题的那一串英文,对于新手来说一定比较陌生,而说起检索,应该都知道吧. 这个ElasticSearch目前我们的首选,他主要有可以提供快速的存储.搜索.分析海量数据的作用.他是一个分布式搜索服务, ...
 - 深入浅出Automation Anywhere
			
Automation Anywhere是基于CLIENT-SERVER架构(control room和客户端),客户端主要是Bot Creator 和 BotRunner 主要构成: 1.WEBCR: ...
 - Zookeeper Ephemeral结点使用心得
			
原文地址:https://www.cnblogs.com/linlemo/p/4807178.html 公司里面在拿Zookeeper做命名服务,通过使用ZK,前端只需要根据指定的ZK地址获得相应的资 ...