BZOJ3123:[SDOI2013]森林
浅谈主席树:https://www.cnblogs.com/AKMer/p/9956734.html
题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=3123
如果是一棵树,维护树上路径第\(k\)大,我们令\(rt[i]\)为加入\(i\)号结点之后主席树的根,若我们在\(rt[fa[i]]\)的基础上建\(rt[i]\)这棵树,那么从每个结点的\(rt[i]\)开始,即可访问原树的根到自己这一条路径上所有权值的\(cnt\),那么\(cnt[u]+cnt[v]-cnt[lca]-cnt[fa[lca]]\)就是路径上在该权值区间内的结点个数。由于题目保证\(u,v\)联通并且路径上的点大于等于\(k\),所以询问就迎刃而解了。
我们考虑对于合并,如果运用启发式合并的思想,每次将大小比较小的树接在大的树上,然后重构小的树,每个点最多会被这样操作\(logn\)次,每次需要更新主席树上对应的根和倍增数组,是\(logn\)复杂度的,所以最后就是\(log^2n\)的。因为每个点最多会被建\(logn\)次,每次会建\(logn\)个节点,所以主席树大小也要开到\(log^2n\)去。
时间复杂度:\(O(nlog^2n)\)
空间复杂度:\(O(nlog^2n)\)
代码如下:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=8e4+5;
int tmp[maxn],a[maxn],rt[maxn];
int n,m,q,cnt,tot,lstans,testcase;
int now[maxn],pre[maxn*2],son[maxn*2];
int dep[maxn],belong[maxn],siz[maxn],f[maxn][18];
int read() {
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
}
struct tree_node {
int cnt,ls,rs;
};
struct chairman_tree {
int tot;
tree_node tree[maxn*17*17];
void ins(int lst,int &now,int l,int r,int pos) {
now=++tot;tree[now]=tree[lst];tree[now].cnt++;
if(l==r)return;
int mid=(l+r)>>1;
if(pos<=mid)ins(tree[lst].ls,tree[now].ls,l,mid,pos);
else ins(tree[lst].rs,tree[now].rs,mid+1,r,pos);
}
int query(int fa1,int fa2,int u,int v,int l,int r,int rk) {
if(l==r)return tmp[l];
int mid=(l+r)>>1;
int sum=tree[tree[u].ls].cnt+tree[tree[v].ls].cnt;
sum-=(tree[tree[fa1].ls].cnt+tree[tree[fa2].ls].cnt);//sum就是路径上值在[l,mid]的节点的个数
if(sum>=rk)return query(tree[fa1].ls,tree[fa2].ls,tree[u].ls,tree[v].ls,l,mid,rk);
return query(tree[fa1].rs,tree[fa2].rs,tree[u].rs,tree[v].rs,mid+1,r,rk-sum);
}
}T;
void add(int a,int b) {
pre[++tot]=now[a];
now[a]=tot;son[tot]=b;
}
void dfs(int fa,int u,int id) {
siz[id]++,belong[u]=id;
f[u][0]=fa,dep[u]=dep[fa]+1;
for(int i=1;i<=17;i++)
f[u][i]=f[f[u][i-1]][i-1];
T.ins(rt[fa],rt[u],1,cnt,a[u]);//每个点建主席树都在父亲主席树基础上建
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(v!=fa)dfs(u,v,id);
}
int lca(int u,int v) {
if(dep[u]<dep[v])swap(u,v);
for(int i=17;~i;i--)
if(dep[f[u][i]]>=dep[v])
u=f[u][i];
if(u==v)return u;
for(int i=17;~i;i--)
if(f[u][i]!=f[v][i])
u=f[u][i],v=f[v][i];
return f[u][0];
}
int main() {
testcase=read();
n=read();m=read();q=read();
for(int i=1;i<=n;i++)
tmp[i]=a[i]=read();
sort(tmp+1,tmp+n+1);
cnt=unique(tmp+1,tmp+n+1)-tmp-1;
for(int i=1;i<=n;i++)
a[i]=lower_bound(tmp+1,tmp+cnt+1,a[i])-tmp;
for(int i=1;i<=m;i++) {
int x=read(),y=read();
add(x,y);add(y,x);
}
for(int i=1;i<=n;i++)
if(!dep[i])dfs(0,i,i);
for(int i=1;i<=q;i++) {
char s[5];scanf("%s",s+1);
int u=read()^lstans,v=read()^lstans;
if(s[1]=='Q') {
int k=read()^lstans;
int fa=lca(u,v);
lstans=T.query(rt[f[fa][0]],rt[fa],rt[u],rt[v],1,cnt,k);
printf("%d\n",lstans);
}
else {
int x=belong[u],y=belong[v];
if(siz[x]>siz[y])swap(x,y),swap(u,v);
add(u,v),add(v,u),dfs(v,u,y);//把小的往大的上合并
}
}
return 0;
}
BZOJ3123:[SDOI2013]森林的更多相关文章
- [bzoj3123][Sdoi2013]森林_主席树_启发式合并
森林 bzoj-3123 Sdoi-2013 题目大意:给定一片共n个点的森林,T个操作,支持:连接两个不在一棵树上的两个点:查询一棵树上路径k小值. 注释:$1\le n,T \le 8\cdot ...
- [BZOJ3123][Sdoi2013]森林 主席树+启发式合并
3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MB Description Input 第一行包含一个正整数testcase,表示当 ...
- BZOJ3123: [Sdoi2013]森林(启发式合并&主席树)
3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 4813 Solved: 1420[Submit][Status ...
- [bzoj3123][sdoi2013森林] (树上主席树+lca+并查集启发式合并+暴力重构森林)
Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数 ...
- 【主席树 启发式合并】bzoj3123: [Sdoi2013]森林
小细节磕磕碰碰浪费了半个多小时的时间 Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M ...
- bzoj3123: [Sdoi2013]森林
题面传送门 复出的第一道题.. md就遇到坑了.. 简单来说就是可持久化线段树+启发式合并啊.. 感觉启发式合并好神奇好想学 每一次建边就暴力合并,每一个节点维护从根到它的权值线段树 按照题面的话最省 ...
- BZOJ3123[Sdoi2013]森林——主席树+LCA+启发式合并
题目描述 输入 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数.第三行包含N个非负 ...
- bzoj千题计划258:bzoj3123: [Sdoi2013]森林
http://www.lydsy.com/JudgeOnline/problem.php?id=3123 启发式合并主席树 #include<cmath> #include<cstd ...
- [bzoj3123] [SDOI2013]森林 主席树+启发式合并+LCT
Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数 ...
- bzoj3123 [Sdoi2013]森林 树上主席树+启发式合并
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3123 题解 如果是静态的查询操作,那么就是直接树上主席树的板子. 但是我们现在有了一个连接两棵 ...
随机推荐
- window+Jira+SQL Server
window下Jira+SQL Server部署+汉化+破解(亲测2018.5) 网上很多都是jira+mysql部署的文章,由于我现在有需求要用SQL Server数据库,因此就动手试了一下,参考网 ...
- C#使用for循环移除HTML标记
public static string StripTagsCharArray(string source) { char[] array = new char[source.Length]; int ...
- JBossWeb/Tomcat 初始化连接器和处理 Http 请求过程
概述 JBossWeb 是JBoss 中的 Web 容器.他是对 Tomcat 的封装,本文以 Http 连接器为例.简单说明 JBossWeb/Tomcat 初始化连接器和处理 Http 请求过程 ...
- N皇后问题算法
N皇后问题的两种主要算法是试探回溯法和位运算法.前一种是经典算法,后一种是目前公认的最高效算法,后者比前者效率提高了至少一个数量级.很多问题可以借鉴位运算的思想. 以下是转载的我认为写的比较好的一篇N ...
- 九度OJ 1061:成绩排序 (排序)
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:17158 解决:4798 题目描述: 有N个学生的数据,将学生数据按成绩高低排序,如果成绩相同则按姓名字符的字母序排序,如果姓名的字母序也相 ...
- 九度OJ 1060:完数VS盈数 (数字特性)
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:5590 解决:2093 题目描述: 一个数如果恰好等于它的各因子(该数本身除外)子和,如:6=3+2+1.则称其为"完数" ...
- Learning an Optimal Policy: Model-free Methods
http://www.mit.edu/~9.54/fall14/slides/Reinforcement%20Learning%202-Model%20Free.pdf [基于所有.单个样本]
- 我的Android进阶之旅------>Android通过使用Matrix旋转图片来模拟碟片加载过程
今天实现了一个模拟碟片加载过程的小demo,在此展示一下.由于在公司,不好截取动态图片,因此就在这截取两张静态图片看看效果先. 下面简单的将代码列出来. setp1.准备两张用于旋转的图片,如下:lo ...
- StreamWriter结合UTF-8编码使用不当,会造成BOM(Byte Order Mark )问题生成乱码(转载)
问: I was using HttpWebRequest to try a rest api in ASP.NET Core MVC.Here is my HttpWebRequest client ...
- [egret+pomelo]实时游戏杂记(3)
[egret+pomelo]学习笔记(1) [egret+pomelo]学习笔记(2) [egret+pomelo]学习笔记(3) 服务端的请求流程走完了一遍,下面就该看一下,在目前的服务端中,各服务 ...