题目链接: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. 关于TCP和MQTT之间的转换

    现在物联网流行的就是MQTT 其实MQTT就是在TCP的基础上建立了一套协议 可以看这个,本来我自己想用Wireshark监听一下,不过百度一搜索一大把,我就不测试了 https://blog.csd ...

  2. php中按值传递和按引用传递的一个问题

    php中传递变量默认是按照值传递. 简单举个例子: <?php function testArray($arr){// &$arr $arr = array(1,2,3,); } $ar ...

  3. Android下WPS打开Excel2007版也有问题

    继上次解决微软office Android版Excel下载并打开Excel文件修改后(http://anforen.com/wp/2017/11/excel-android-mobile/),再上传出 ...

  4. BZOJ 3561 DZY Loves Math VI

    BZOJ 3561 DZY Loves Math VI 求\(\sum_{i=1}^{n}\sum_{j=1}^{m}\text{lcm}(i,j)^{\gcd(i,j)}\),钦定\(n\leq m ...

  5. Centos下安装破解Jira7的操作记录

    Jira是一个集项目计划.任务分配.需求管理.错误跟踪于一体的工具,可以作为一个bug管理系统,可以将在测试过程中所发现的bug录入.分配给开发人员.前面介绍了Confluence在Centos下的安 ...

  6. centos6.5虚拟机安装后,没有iptables配置文件

    openstack环境里安装centos6.5系统的虚拟机,安装好后,发现没有/etc/syscofig/iptables防火墙配置文件. 解决办法如下: [root@kvm-server005 ~] ...

  7. kvm虚拟化管理平台WebVirtMgr部署-完整记录(0)

    打算部署kvm虚拟机环境,下面是虚拟化部署前的一些准备工作: 操作系统环境安装1)修改内核模式为兼容内核启动[root@ops ~]# uname -aLinux openstack 2.6.32-4 ...

  8. JS冷门知识盘点

    (+new Date() 是简略写法,得到毫秒 超过多行显示省略号 overflow : hidden; text-overflow: ellipsis; display: -webkit-box; ...

  9. box-flex 弹性合布局+WebApp布局自适应

    问:随着屏幕改变,中间自适应 两边固定宽度? 参考: nec 布局 四种方法--博客园 问:左侧导航栏隐藏后,右侧内容宽度自动(响应式)变大? <!DOCTYPE html> <ht ...

  10. Safecracker-HDU1015

    题意 给你大写字母的字符串,A=1,...Z=26,以及target 问你是否有v - w^2 + x^3 - y^4 + z^5 = target 有输出字典序大的那个字符串 分析 dfs code ...