我们直接按父子关系建主席树,然后记录倍增方便以后求LCA,同时用并查集维护根节点,而且还要记录根节点对应的size,用来对其启发式合并,然后每当我们合并的时候我们都要暴力拆小的一部分重复以上部分,总时间复杂度为O(n*log),因为每个的节点只会作为小的部分合并,因此他所在的一小部分至少变大2倍,对于每一个节点他作为被合并方最多log次,因此其复杂度为O(n*log),而这个是绝对跑不满还差很多的,我们视他为无常数就好了,当然这一切都是建立在无拆分操作的基础之上,只要有了拆分启发式合并的复杂度就是暴力了。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAXN 80001
using namespace std;
inline int read(){
register int sum=;register char ch=getchar();
while(ch<''||ch>'')ch=getchar();
while(ch>=''&&ch<='')sum=(sum<<)+(sum<<)+ch-'',ch=getchar();
return sum;
}
int n,m,T,fa[MAXN],size[MAXN],f[MAXN][];
struct Via{
int to,next;
}c[MAXN<<];
int head[MAXN],t;
struct Seg_Tree{
Seg_Tree *ch[];
int size;
}*root[MAXN],*null;
int pos[MAXN],a[MAXN],deep[MAXN];
int Hash[MAXN],len;
bool v[MAXN];
//*********************Define********************//
inline int find(int x){
return x==fa[x]?x:(fa[x]=find(fa[x]));
}
inline void Unit_to_(int x,int y){
fa[find(x)]=find(y);
}
//*******************Union_Find_Sets*************//
inline void add(int x,int y){
c[++t].to=y,c[t].next=head[x],head[x]=t;
}
//********************Maintain_Tree**************//
int comp(const int x,const int y){
return a[x]<a[y];
}
inline void HASH(){
sort(pos+,pos+n+,comp);
for(register int i=;i<=n;i++)
if(i==||a[pos[i]]!=a[pos[i-]])Hash[++len]=a[pos[i]],a[pos[i]]=len;
else a[pos[i]]=len;
}
//********************Hash**********************//
void ins(Seg_Tree *&p,Seg_Tree *last,int l,int r,int key){
p=new Seg_Tree,*p=*last,++p->size;if(l==r)return;
if(key<=((l+r)>>))ins(p->ch[],last->ch[],l,((l+r)>>),key);
else ins(p->ch[],last->ch[],((l+r)>>)+,r,key);
}
void Dfs_Build(int x,int Fa){
deep[x]=deep[Fa]+;v[x]=;
for(register int i=;i<;i++)f[x][i]=f[f[x][i-]][i-];
ins(root[x],root[Fa],,len,a[x]);
for(register int i=head[x];i;i=c[i].next)
if(c[i].to!=Fa) f[c[i].to][]=x,Dfs_Build(c[i].to,x);
}
int query(Seg_Tree *A1,Seg_Tree *A2,Seg_Tree *B1,Seg_Tree *B2,int l,int r,int k){
if(l==r)return l;register int sum=A1->ch[]->size-A2->ch[]->size+B1->ch[]->size-B2->ch[]->size;
if(sum>=k)return query(A1->ch[],A2->ch[],B1->ch[],B2->ch[],l,((l+r)>>),k);
else return query(A1->ch[],A2->ch[],B1->ch[],B2->ch[],((l+r)>>)+,r,k-sum);
}
void Del(Seg_Tree *p,Seg_Tree *last){
if(p==last)return;
Del(p->ch[],last->ch[]),Del(p->ch[],last->ch[]);
delete p;
}
void Delete(int x,int fa){
for(register int i=head[x];i;i=c[i].next)
if(c[i].to!=fa)Delete(c[i].to,x);
Del(root[x],root[fa]),root[x]=null;
}
//********************Seg_Tree******************//
inline int Lca(int x,int y){
if(deep[x]<deep[y])x^=y^=x^=y;
register int k=deep[x]-deep[y];
for(register int i=;(<<i)<=k;i++)
if(k&(<<i)) x=f[x][i];
if(x==y)return x;
for(register int i=;i>=;i--)
if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
return f[x][];
}
//*********************LCA*********************//
inline void Init(){
scanf("%*d"),n=read(),m=read(),T=read();
null=new Seg_Tree,null->ch[]=null->ch[]=null,null->size=,root[]=null;
for(register int i=;i<=n;i++)a[i]=read(),pos[i]=i,root[i]=null,size[i]=,fa[i]=i;HASH();
for(register int i=,x,y;i<=m;i++)x=read(),y=read(),add(x,y),add(y,x),size[find(y)]+=size[find(x)],Unit_to_(x,y);
for(register int i=;i<=n;i++)if(!v[i])Dfs_Build(find(i),);
}
inline void Work(){
register int x,y,k,lca,ans=;register char s[];
while(T--){
scanf("%s",s);
if(s[]=='Q'){
x=read()^ans,y=read()^ans,k=read()^ans,lca=Lca(x,y);
printf("%d\n",(ans=Hash[query(root[x],root[lca],root[y],root[f[lca][]],,len,k)]));
}else{
x=read()^ans,y=read()^ans;if(size[find(x)]>size[find(y)])x^=y^=x^=y;
Delete(find(x),),size[find(y)]+=size[find(x)],Unit_to_(x,y);
f[x][]=y,add(x,y),add(y,x),Dfs_Build(x,y);
}
}
}
//*********************Main********************//
int main(){
Init();
Work();
return ;
}

【BZOJ 3123】 [Sdoi2013]森林 主席树启发式合并的更多相关文章

  1. Bzoj 3123: [Sdoi2013]森林(主席树+启发式合并)

    3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MB Description Input 第一行包含一个正整数testcase,表示当前 ...

  2. BZOJ 3123: [Sdoi2013]森林 [主席树启发式合并]

    3123: [Sdoi2013]森林 题意:一个森林,加边,询问路径上k小值.保证任意时刻是森林 LCT没法搞,树上kth肯定要用树上主席树 加边?启发式合并就好了,小的树dfs重建一下 注意 测试点 ...

  3. [bzoj3123] [SDOI2013]森林 主席树+启发式合并+LCT

    Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数 ...

  4. [BZOJ3123][Sdoi2013]森林 主席树+启发式合并

    3123: [Sdoi2013]森林 Time Limit: 20 Sec  Memory Limit: 512 MB Description Input 第一行包含一个正整数testcase,表示当 ...

  5. luoguP3302 [SDOI2013]森林 主席树 启发式合并

    题目链接 luoguP3302 [SDOI2013]森林 题解 本来这题树上主席树暴力启发式合并就完了 结果把lca写错了... 以后再也不这么写了 复杂度\(O(nlog^2n)\) "f ...

  6. [SDOI2013]森林 主席树+启发式合并

    这题的想法真的很妙啊. 看到题的第一眼,我先想到树链剖分,并把\(DFS\)序当成一段区间上主席树.但是会发现在询问的时候,可能会非常复杂,因为你需要把路径拆成很多条轻链和重链,它们还不一定连续,很难 ...

  7. 【BZOJ-3123】森林 主席树 + 启发式合并

    3123: [Sdoi2013]森林 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2738  Solved: 806[Submit][Status] ...

  8. bzoj 3123 可持久化线段树启发式合并

    首先没有连边的操作的时候,我们可以用可持久化线段树来维护这棵树的信息,建立权值可持久化线段树,那么每个点继承父节点的线段树,当询问为x,y的时候我们可以询问rot[x]+rot[y]-rot[lca( ...

  9. P3302 [SDOI2013]森林(主席树+启发式合并)

    P3302 [SDOI2013]森林 主席树+启发式合并 (我以前的主席树板子是错的.......坑了我老久TAT) 第k小问题显然是主席树. 我们对每个点维护一棵包含其子树所有节点的主席树 询问(x ...

随机推荐

  1. 理解HBase

    1.HBase HBase: Hadoop Database,根据Google的Big Table设计 HBase是一个分布式.面向列族的开源数据库.HDFS为Hbase提供了底层的数据存储服务,Ma ...

  2. ELK 分布式日志实战

    一.  ELK 分布式日志实战介绍 此实战方案以 Elk 5.5.2 版本为准,分布式日志将以下图分布进行安装部署以及配置. 当Elk需监控应用日志时,需在应用部署所在的服务器中,安装Filebeat ...

  3. hive 学习系列三(表格的创建create-table)

    表格创建: 语法 第一种建表的形式: 说明: temporary 临时表,在当前回话内,这张表有效,当回话结束,可以理解为程序结束,则程序终止. external 外部表, hdfs 上的表的文件,并 ...

  4. SGU 495

    #include<bits/stdc++.h> using namespace std; #define ll long long ; ; int n,m; double dp[N]; / ...

  5. 【转】Linux系统安装Redis详细过程

    本文来源 https://blog.csdn.net/qq_20989105/article/details/76390367 ,转载前请先联系原作者并声明出处. 一.安装gcc 1.Redis在li ...

  6. php简易实现计划任务

    index.php <?php function ceshi(){ $wan = file_get_contents('./wangt_index.txt',true); $jifen = $w ...

  7. 记一次艰难的CTP调试

    一个atmel,mxt540e的CTP触摸屏. 中断配置为下降沿,输入上拉. 总是只能触发一次中断,中断脚就一直低电平,无法拉高.这只是表面现象   不停找底层I2C驱动,改代码,没用.要靠波形来说话 ...

  8. 如何理解Java中参数传递只能传值?

    以前学习C#的时候,是完全在工作岗位上学习,一些底层较为深入的道理都不是很清楚.如今学习了Java,对于Java参数传递只能传值,不能传引用(指针)感到很困惑,在C#中不是常常说把某个引用传递到函数中 ...

  9. nodejs的交叉(跨平台)编译(to android)

    nodejs的二进制包有两种安装方式node-gyp以及node-pre-gyp 这两条命令会写入该包的安装脚本. node-gyp是使用gyp工具编译源码,因此必须指定交叉编译器(参见http:// ...

  10. Linux-Shell脚本编程-学习-6-Shell编程-使用结构化命令-文件比较-case编程

    这一片主要说test文件的比较,文件比较在日常使用的频率比较高,这里重点把每个部分都试着说说看 1. 检车目录 -d -d测试会检查指定的文件名是否在系统上以目录的形式存在,当我们要写文件到某个目录之 ...