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 ...
随机推荐
- jmeter(十二)关联之正则表达式提取器
如果有这样的情况:一个完整的操作流程,需要先完成某个操作,获得某个值或数据信息,然后才能进行下一步的操作(也就是常说的关联/将上一个请求的响应结果作为下一个请求的参数): 在jmeter中,可以利用正 ...
- java.lang.UnsatisfiedLinkError: No implementation found for int com.baidu.platform.comjni.map.commonmemcache.JNICommonMemCache.Create()
完整异常: Process: com.example.ai.tabhostdemo, PID: 1287 java.lang.UnsatisfiedLinkError: No implementati ...
- [05] 动态SQL
MyBatis的强大特性之一就是它的动态SQL,它可以根据不同的条件动态地组成SQL语句进行执行.为此,MyBatis提供了一系列强大的表达式,本章将就此进行学习,主要内容直接参考的是官方文档< ...
- SQL2005中的事务与锁定(九)-(2)- 转载
-------------------------------------------------------------------------- Author : HappyFlyStone -- ...
- CF700E Cool Slogans SAM、线段树合并、树形DP
传送门 在最优的情况下,序列\(s_1,s_2,...,s_k\)中,\(s_i (i \in [2 , k])\)一定会是\(s_{i-1}\)的一个\(border\),即\(s_i\)同时是\( ...
- Luogu3877 TJOI2010 打扫房间 二分图、网络流
传送门 真是菜死了模板题都不会-- 首先\(30 \times 30\)并不能插头DP,但是范围仍然很小所以考虑网络流. 注意每个点都要包含在一个回路中,那么每一个点的度数都必须为\(2\),也就是说 ...
- Luogu P3825 [NOI2017]游戏
这道题看上去NPC啊,超级不可做的样子. 我们先分析一下简单的情形:没有\(x\)地图 此时每个地图由于限制掉一种汽车,那么显然只会有两种选择. 再考虑到限制的情况,那么大致做法就很显然了--2-SA ...
- Jumpserver双机高可用环境部署笔记
之前在IDC部署了Jumpserver堡垒机环境,作为登陆线上服务器的统一入口.后面运行一段时间后,发现Jumpserver服务器的CPU负载使用率高达80%以上,主要是python程序对CPU的消耗 ...
- Zookeeper Ephemeral结点使用心得
原文地址:https://www.cnblogs.com/linlemo/p/4807178.html 公司里面在拿Zookeeper做命名服务,通过使用ZK,前端只需要根据指定的ZK地址获得相应的资 ...
- BUAAMOOC项目M2 postmortem
设想和目标 1.我们的软件要解决什么问题?是否定义的很清楚?是否对典型用户和典型场景有清晰的描述? 我们的软件是基于北航MOOC网站做的Android手机客户端,用于便捷的在学校里通过手机做到随时随地 ...