BZOJ 3123: [Sdoi2013]森林 [主席树启发式合并]
3123: [Sdoi2013]森林
题意:一个森林,加边,询问路径上k小值。保证任意时刻是森林
LCT没法搞,树上kth肯定要用树上主席树
加边?启发式合并就好了,小的树dfs重建一下
注意
- 测试点编号不是数据组数!!!
- 加边的时候要更新邻接链表啊,并且fa要清空
- 并查集维护size一定初始化1
好了现在我要填报名表了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
#define lc(x) t[x].l
#define rc(x) t[x].r
const int N=1e5+5, M=2e5+5;
inline int read(){
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
int n, m, Q, a[N], u, v, k, mp[N]; char s[5];
namespace ufs{
int fa[N], size[N];
int find(int x) {return x==fa[x]?x:fa[x]=find(fa[x]);}
} using ufs::size; using ufs::find;
struct edge{int v,ne;}e[M];
int cnt, h[N];
inline void ins(int u, int v) {
e[++cnt]=(edge){v, h[u]}; h[u]=cnt;
e[++cnt]=(edge){u, h[v]}; h[v]=cnt;
}
int vis[N], fa[N][18], deep[N];
int lca(int x, int y) {
if(deep[x]<deep[y]) swap(x, y);
int bin=deep[x]-deep[y];
for(int i=0; i<17; i++) if((1<<i)&bin) x=fa[x][i];
if(x==y) return x;
for(int i=16; i>=0; i--)
if(fa[x][i] != fa[y][i]) x=fa[x][i], y=fa[y][i];
return fa[x][0];
}
struct ChairTree{
struct meow{int l,r,size;}t[N*85];
int sz, root[N];
void insert(int &x, int l, int r, int p) {
t[++sz]=t[x]; x=sz;
t[x].size++;
if(l==r) return;
int mid=(l+r)>>1;
if(p<=mid) insert(lc(x), l, mid, p);
else insert(rc(x), mid+1, r, p);
}
void build(int u) { //printf("build %d %d\n",u,fa[u][0]);
vis[u]=1;
for(int i=1; (1<<i)<=deep[u]; i++)
fa[u][i] = fa[ fa[u][i-1] ][i-1];
root[u] = root[fa[u][0]];
insert(root[u], 1, *mp, a[u]);
for(int i=h[u];i;i=e[i].ne)
if(e[i].v != fa[u][0]) {
fa[e[i].v][0]=u; deep[e[i].v]=deep[u]+1;
build(e[i].v);
}
}
int query(int u, int v, int k) {
int f=lca(u,v), g=fa[f][0];
int x=root[u], y=root[v], l=1, r=*mp; f=root[f]; g=root[g];
while(l!=r) {
int lsize = t[lc(x)].size + t[lc(y)].size - t[lc(f)].size - t[lc(g)].size;
int mid=(l+r)>>1;
if(k<=lsize) x=lc(x), y=lc(y), f=lc(f), g=lc(g), r=mid;
else x=rc(x), y=rc(y), f=rc(f), g=rc(g), l=mid+1, k-=lsize;
}
return l;
}
void rebuild(int u) {
for(int i=1; i<17; i++)
fa[u][i] = fa[ fa[u][i-1] ][i-1];
root[u] = root[fa[u][0]];
insert(root[u], 1, *mp, a[u]);
for(int i=h[u];i;i=e[i].ne)
if(e[i].v != fa[u][0]) {
fa[e[i].v][0]=u; deep[e[i].v]=deep[u]+1;
rebuild(e[i].v);
}
}
void Link(int u, int v) {
int x=find(u), y=find(v);
if(size[x]<size[y]) swap(x, y), swap(u, v);
ufs::fa[y]=x; size[x]+=size[y];
ins(u, v);
fa[v][0]=u; deep[v]=deep[u]+1;
rebuild(v);
}
}C;
int candy;
int main() {
freopen("in","r",stdin);
int T=read(); T+=2333;
n=read(); m=read(); Q=read();
for(int i=1; i<=n; i++) a[i]=mp[i]=read(), ufs::fa[i]=i, size[i]=1;
sort(mp+1, mp+1+n); mp[0]=unique(mp+1, mp+1+n)-mp-1;
for(int i=1; i<=n; i++) a[i] = lower_bound(mp+1, mp+1+*mp, a[i])-mp;
for(int i=1; i<=m; i++) {
u=read(), v=read();
ins(u,v);
u=find(u); v=find(v);
ufs::fa[v]=u; size[u]+=size[v];
}
for(int i=1; i<=n; i++) if(!vis[i]) C.build(i);
int ans=0;
//candy=1;
for(int i=1; i<=Q; i++) {
scanf("%s",s);
if(candy) u=read(), v=read();
else u=read()^ans, v=read()^ans;
if(s[0]=='Q') {
if(candy) k=read();
else k=read()^ans;
ans = mp[C.query(u, v, k)];
printf("%d\n", ans);
}else C.Link(u, v);
}
}
BZOJ 3123: [Sdoi2013]森林 [主席树启发式合并]的更多相关文章
- Bzoj 3123: [Sdoi2013]森林(主席树+启发式合并)
3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MB Description Input 第一行包含一个正整数testcase,表示当前 ...
- [bzoj3123] [SDOI2013]森林 主席树+启发式合并+LCT
Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数 ...
- [BZOJ3123][Sdoi2013]森林 主席树+启发式合并
3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MB Description Input 第一行包含一个正整数testcase,表示当 ...
- 【BZOJ 3123】 [Sdoi2013]森林 主席树启发式合并
我们直接按父子关系建主席树,然后记录倍增方便以后求LCA,同时用并查集维护根节点,而且还要记录根节点对应的size,用来对其启发式合并,然后每当我们合并的时候我们都要暴力拆小的一部分重复以上部分,总时 ...
- luoguP3302 [SDOI2013]森林 主席树 启发式合并
题目链接 luoguP3302 [SDOI2013]森林 题解 本来这题树上主席树暴力启发式合并就完了 结果把lca写错了... 以后再也不这么写了 复杂度\(O(nlog^2n)\) "f ...
- [SDOI2013]森林 主席树+启发式合并
这题的想法真的很妙啊. 看到题的第一眼,我先想到树链剖分,并把\(DFS\)序当成一段区间上主席树.但是会发现在询问的时候,可能会非常复杂,因为你需要把路径拆成很多条轻链和重链,它们还不一定连续,很难 ...
- 【BZOJ-3123】森林 主席树 + 启发式合并
3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 2738 Solved: 806[Submit][Status] ...
- bzoj 3123 可持久化线段树启发式合并
首先没有连边的操作的时候,我们可以用可持久化线段树来维护这棵树的信息,建立权值可持久化线段树,那么每个点继承父节点的线段树,当询问为x,y的时候我们可以询问rot[x]+rot[y]-rot[lca( ...
- P3302 [SDOI2013]森林(主席树+启发式合并)
P3302 [SDOI2013]森林 主席树+启发式合并 (我以前的主席树板子是错的.......坑了我老久TAT) 第k小问题显然是主席树. 我们对每个点维护一棵包含其子树所有节点的主席树 询问(x ...
随机推荐
- hdu_1754I Hate It(线段树)
hdu_1754I Hate It(线段树) 标签: 线段树 题目链接 题意: 中文题意...不多说了,线段树基础题 直接上代码: #include<cstdio> #include< ...
- java的finalize()方法与C++的析构函数
---<java编程思想> 读书笔记 --- 2017/3/15 读<java编程思想>读到初始化与清理一章,文中提及java的finalize()方法,联想到了C++的析构函 ...
- python数据类型(二)
一.List(列表) List(列表) 是 Python 中使用最频繁的数据类型. 列表可以完成大多数集合类的数据结构实现.列表中元素的类型可以不相同,它支持数字,字符串甚至可以包含列表(所谓嵌套). ...
- 常用Windows DOS命令项目部署经常用到
img { max-width: 100% } 前两天部署.netcore项目,首先是生产环境域名访问不了,再到.netcore项目IIS部署502.5,在到莫名其妙的500,在排查项目部署问题的时候 ...
- [国嵌攻略][061][2440LCD驱动设计]
LCD初始化 1.引脚初始化 2.时序初始化 VBPD(vertical back porch):表示在一帧图像开始时,垂直同步信号以后的无效的行数 VFBD(vertical front porch ...
- Oracle_SQL99_连接查询
Oracle_SQL99_连接查询 交叉连接 cross join --交叉连接 cross join --作用:产生两个表的笛卡尔积 select * from emp cross join d ...
- KEIL MDK 查看代码量、RAM使用情况--RO-data、RW-data、ZI-data
KEIL RVMDK编译后的信息 Code是代码占用的空间, RO-data是 Read Only 只读常量的大小,如const型, RW-data是(Read Write) 初始化了的可读写变量的大 ...
- 基于VUE选择上传图片并在页面显示(图片可删除)
demo例子: 依赖文件 : http://files.cnblogs.com/files/zhengweijie/jquery.form.rar HTML文本内容: <template> ...
- 深入理解:Linear Regression及其正则方法
这是最近看到的一个平时一直忽略但深入研究后发现这里面的门道还是很多,Linear Regression及其正则方法(主要是Lasso,Ridge, Elastic Net)这一套理论的建立花了很长一段 ...
- Thrift之TProtocol系列TBinaryProtocol解析
首先看一下Thrift的整体架构,如下图: 如图所示,黄色部分是用户实现的业务逻辑,褐色部分是根据thrift定义的服务接口描述文件生成的客户端和服务器端代码框架(前篇2中已分析了thrift ser ...