[bzoj3123][Sdoi2013]森林_主席树_启发式合并
森林 bzoj-3123 Sdoi-2013
题目大意:给定一片共n个点的森林,T个操作,支持:连接两个不在一棵树上的两个点;查询一棵树上路径k小值。
注释:$1\le n,T \le 8\cdot 10^4$
想法:运用冯老师讲的方法:
“对于一个开起来非常困难的问题,我们可以通过先构造拟对象,然后向完全对象转化”
这个题,我们看到了最后一个操作,想到了主席树。
两个点x、y之间的路径,我们在主席树上用root[x]+root[y]-root[lca(x,y)]-root[fa[lca(x,y)]]的权值线段树即可。
那么,如果加上连接操作呢?
直接启发式合并,然后重置一部分的主席树即可。(重置的时候记得把倍增的数组也重置)
最后,附上丑陋的代码... ...
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
using namespace std;
int cnt,tot,ans,len,a,b,tcase,n,m,q;
char s[5];
int x,y,z,d[80010],h[80010],v[80010];
map<int,int>g;
int to[200010],vis[80010],anc[80010],size[80010],ls[20000010],rs[20000010],nxt[200010],head[200010],f[80010][26],sum[20000010],root[2000010];
inline void add(int x,int y)
{
to[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
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<=23;i++)
{
if((dep&(1<<i))!=0)
{
x=f[x][i];
}
}
if(x==y)
{
return x;
}
for(int i=23;i>=0;i--)
{
if(f[x][i]!=f[y][i])
{
x=f[x][i];
y=f[y][i];
}
}
return f[x][0];
}
int updata(int pre,int l,int r,int v)
{
int pos=++cnt,mid=(l+r)>>1;
ls[pos]=ls[pre];
rs[pos]=rs[pre];
sum[pos]=sum[pre]+1;
if(l==r)
{
return pos;
}
else
{
if(v<=mid)
{
ls[pos]=updata(ls[pre],l,mid,v);
}
else
{
rs[pos]=updata(rs[pre],mid+1,r,v);
}
}
return pos;
}
int query(int x,int y,int fa,int anc,int l,int r,int k)
{
int mid=(l+r)>>1;
if(l==r)
{
return g[l];
}
int num=sum[ls[x]]+sum[ls[y]]-sum[ls[fa]]-sum[ls[anc]];
if(k<=num)
{
return query(ls[x],ls[y],ls[fa],ls[anc],l,mid,k);
}
else
{
return query(rs[x],rs[y],rs[fa],rs[anc],mid+1,r,k-num);
}
}
void dfs(int x,int fa,int ac)
{
vis[x]=1;
anc[x]=ac;
f[x][0]=fa;
d[x]=d[fa]+1;
root[x]=updata(root[fa],1,n,v[x]);
for(int i=1;i<=23;i++)
{
f[x][i]=f[f[x][i-1]][i-1];
}
for(int i=head[x];i;i=nxt[i])
{
if(to[i]!=fa)
{
dfs(to[i],x,ac);
size[x]+=size[to[i]];
}
}
}
int main()
{
scanf("%d",&tcase);
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;i++)
{
scanf("%d",&v[i]);
h[i]=v[i];
size[i]=1;
}
sort(h+1,h+1+n);
len=unique(h+1,h+1+n)-h-1;
for(int i=1;i<=n;i++)
{
int val=v[i];
v[i]=lower_bound(h+1,h+1+len,v[i])-h;
g[v[i]]=val;
}
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
for(int i=1;i<=n;i++)
{
if(vis[i]) continue;
dfs(i,0,i);
}
while(q--)
{
scanf("%s",s);
if(s[0]=='Q')
{
scanf("%d%d%d",&x,&y,&z);
x=x^ans;
y=y^ans;
z=z^ans;
a=lca(x,y);
b=f[a][0];
ans=query(root[x],root[y],root[a],root[b],1,n,z);
printf("%d\n",ans);
}
else
{
scanf("%d%d",&x,&y);
x=x^ans;
y=y^ans;
add(x,y);
add(y,x);
if(size[anc[x]]<size[anc[y]])
{
size[anc[y]]+=size[anc[x]];
dfs(x,y,anc[y]);
}
else
{
size[anc[x]]+=size[anc[y]];
dfs(y,x,anc[x]);
}
}
}
}
小结:主席树活用起来真tm吓人... ...
[bzoj3123][Sdoi2013]森林_主席树_启发式合并的更多相关文章
- 【BZOJ3123】森林(主席树,启发式合并)
题意:一个带点权的森林,要求维护以下操作: 1.询问路径上的点权K大值 2.两点之间连边 n,m<=80000 思路:如果树的结构不发生变化只需要维护DFS序 现在因为树的结构发生变化,要将两棵 ...
- [bzoj3123][sdoi2013森林] (树上主席树+lca+并查集启发式合并+暴力重构森林)
Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数 ...
- bzoj3123 [Sdoi2013]森林 树上主席树+启发式合并
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3123 题解 如果是静态的查询操作,那么就是直接树上主席树的板子. 但是我们现在有了一个连接两棵 ...
- bzoj 3123 [Sdoi2013]森林(主席树+启发式合并+LCA)
Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数 ...
- BZOJ3123[Sdoi2013]森林——主席树+LCA+启发式合并
题目描述 输入 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数.第三行包含N个非负 ...
- P3302 [SDOI2013]森林(主席树+启发式合并)
P3302 [SDOI2013]森林 主席树+启发式合并 (我以前的主席树板子是错的.......坑了我老久TAT) 第k小问题显然是主席树. 我们对每个点维护一棵包含其子树所有节点的主席树 询问(x ...
- bzoj 3123 [Sdoi2013]森林(主席树,lca,启发式合并)
Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数 ...
- BZOJ2123 [Sdoi2013]森林 【主席树 + 启发式合并】
题目 输入格式 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数.第三行包含N个非负 ...
- [luoguP3302] [SDOI2013]森林(主席树 + 启发式合并 + lca)
传送门 显然树上第k大直接主席树 如果连边的话,我们重构小的那一棵,连到另一棵上. 说起来简单,调了我一晚上. 总的来说3个错误: 1.离散化写错位置写到了后面 2."="写成了& ...
随机推荐
- P1228 地毯填补问题(分治)
P1228 地毯填补问题(分治) 题目描述 相传在一个古老的阿拉伯国家里,有一座宫殿.宫殿里有个四四方方的格子迷宫,国王选择驸马的方法非常特殊,也非常简单:公主就站在其中一个方格子上,只要谁能用地毯将 ...
- constraint和index--转载
primary key和unique约束是要依赖index的,下面通过试验来看看他们之间的依赖关系! SQL> select * from tt; ID NA --------- ...
- 两个向量之间的欧式距离及radial-basis-functions(RBF)
template <class DataType1, class DataType2>double EuclideanDistance(std::vector<DataType1&g ...
- bzoj2115
线性基+dfs树 我们先搞出dfs树,其实最终路径就是最初的路径和一些环异或. 环最多只有m-n+1,因为一共有m条边,然后有n-1条边在dfs树上,所以还剩m-n+1条边,都可以构成环. 所以dfs ...
- go package包的使用
一.标准库 引入 在我们之前所写的所以代码中,我们基本上可以看到fmt这个导入的包,但是我们却不知道如何去写这种包. 如果我们可以自己去写,那么我们就可以将一个功能的集合统一的放入包中,便于以后使用, ...
- C99C新增内容
继上一篇复合文字之后,今天我们继续谈一谈C99C的新特性. C99标准是继C89标准之后的第二个C语言官方标准,于1999年12月1日正式发布,其中对数据类型(增加了对_Bool),关键字(增加了in ...
- django-2的路由层(URLconf)
URL配置(URLconf)就像Django 所支撑网站的目录.它的本质是URL与要为该URL调用的视图函数之间的映射表:你就是以这种方式告诉Django,对于客户端发来的某个URL调用哪一段逻辑代码 ...
- Hibernate多表映射(三)
一对多|多对一 一个分类对应多个商品,一个商品只属于一个分类 创建分类表 products用set装,set特点值不能够重复 package com.hibernate.domain; import ...
- Laravel5.1 学习笔记2, 路由
安装的说明请看文档, laravel 安装 #基本路由 你将在 app/Http/routes.php 文件定义大部分路由, 这些路由将被App\Providers\RouteServiceProvi ...
- ie8及其以下版本兼容性问题之placeholder实现
1. 普通浏览器下修改placeholder颜色 因为每个浏览器的CSS选择器都有所差异,所以需要针对每个浏览器做单独的设定. 示例: input::-webkit-input-placeholder ...