笼统的主席树原理

众所周知, 主席树是可以持久化的, 换言之你能知道你所维护信息的所有历史状态。 主席树是这样做的:

1.

首先建一颗朴素的线段树,代表初始状态 (下图黑色) , 也就是第0次操作后的状态。

tipA:

你每次只对一个叶子节点的数据进行更新,所以相当于更改了树上的一条链。

2.

我们不在原来的树上修改,而是创建若干个新的节点组成一条链代表树中修改后的各个节点 (下图红色) ,然后直接把这条链糊到树上, 并且让新链中的每个节点都连好它在树中应该连的节点 (下图蓝色)

tipB:

你会发现只要交换新旧链, 就可以得到两颗完整的树

tipC:

你还会发现:在每次更新中添加的新链,都会包含树的根节点,所以你只需要记录下第[0 - N]次操作后的树的根节点,就可以通过某一个根节点得到特定历史版本的树。
(0次操作后的根节点是黑色树根, 1次操作后的根节点是红色树根)

3.

然 后 随 便 van van , 主 席 树 就 学 完 了。

4.

然后我们就可以滚到别的题解上爬了

主席树 luogu.com.cn 的主席树板子

纯区间第K大
区间[r - (l - 1)] 相当于只插入了[l - r] 然后直接找。

#include <bits/stdc++.h>const int N = 2e5+4;
int lst[N]/*原序列*/, srt[N]/*排序数组*/, root[N]/*记录树根*/;
int sum[N<<5], L[N<<5], R[N<<5];
int n, m, ql, qr, k, idx, sn;int build(int l, int r){int rt = ++idx, mid = (l + r) >> 1;if(l < r){L[rt] = build(l, mid);R[rt] = build(mid + 1, r);}return rt;
}int update(int pre, int l, int r, int k){int rt = ++idx, mid = (l + r) >> 1;L[rt] = L[pre], R[rt] = R[pre], sum[rt] = sum[pre] + 1;if(l < r){if(k <= mid) L[rt] = update(L[pre], l, mid, k);else R[rt] = update(R[pre], mid + 1, r, k);}return rt;
}int query(int ql, int qr, int l, int r, int k){if( l >= r) return l;int num = sum[L[qr]] - sum[L[ql]], mid = (l + r) >> 1;if(num >= k) return query(L[ql], L[qr], l, mid, k);else return query(R[ql], R[qr], mid + 1, r, k - num);
}int main(){scanf("%d%d", &n, &m);for(int i=1; i<=n; i++){scanf("%d", &lst[i]);srt[i] = lst[i];}std::sort(srt + 1, srt + 1 + n);sn = std::unique(srt + 1, srt + 1 + n) - srt - 1;root[0] = build(1, sn);for(int i=1; i<=n; i++){k = std::lower_bound(srt + 1, srt + 1 + sn, lst[i]) - srt;root[i] = update(root[i - 1], 1, sn, k);}while(m --){scanf("%d%d%d", &ql, &qr, &k);n = query(root[ql - 1], root[qr], 1, sn, k);printf("%d\n", srt[n]);}return 0;
}

主席树+并查集 luogu.com.cn 的可持久化并查集板子

纯并查集

#include <bits/stdc++.h>const int N = 1e5 + 4, M = 2e5 + 4;
int n, q, idx, x, y, op, xx, yy;
int D[M << 5], F[M << 5], L[M << 5], R[M << 5], E[M];int build(int l, int r){int rt = ++idx;if(l == r) { F[rt] = l, D[rt] = 1; return rt; }int mid = (l + r) >> 1;L[rt] = build(l, mid);R[rt] = build(mid + 1, r);return rt;
}int update(int pre, int l, int r, int k, int f){int rt = ++idx;if(l == r){D[rt] = D[pre];F[rt] = f;return rt;}L[rt] = L[pre], R[rt] = R[pre];int mid = (l + r) >> 1;if(k <= mid) L[rt] = update(L[pre], l, mid, k , f);else R[rt] = update(R[pre], mid + 1, r, k, f);return rt;
}int query(int rt, int l, int r, int k){if(l == r) return rt;int mid = (l + r) >> 1;if(k <= mid) return query(L[rt], l, mid, k);return query(R[rt], mid + 1, r, k);
}void cd(int rt, int l, int r, int k){if(l == r) {D[rt] += 1; return ;}int mid = (l + r) >> 1;if(k <= mid) cd(L[rt], l, mid, k);else cd(R[rt], mid + 1, r, k);
}int ffind(int rt, int x){int t = query(rt, 1, n, x);if(x == F[t]) return t;return ffind(rt, F[t]);
}int main(){scanf("%d%d", &n, &q);E[0] = build(1, n);for(int i=1; i<=q; i++){scanf("%d", &op);if(op == 1){scanf("%d%d", &x, &y);E[i] = E[i - 1];xx = ffind(E[i], x), yy = ffind(E[i], y);if(D[xx] > D[yy]) std::swap(xx, yy);E[i] = update(E[i - 1], 1, n, F[xx], F[yy]);if(D[xx] + 1 > D[yy]) cd(E[i], 1, n, F[yy]);}if(op == 2){scanf("%d", &x);E[i] = E[x];}if(op == 3){scanf("%d%d", &x, &y);E[i] = E[i - 1];xx = ffind(E[i], x), yy = ffind(E[i], y);printf("%d\n", F[xx] == F[yy] ? 1 : 0);}}return 0;
}

可持久化线段树【主席树】可持久化并查集【主席树+并查集】相关推荐

  1. 解题报告:P3834 【模板】可持久化线段树 2(主席树)详解

    P3834 [模板]可持久化线段树 2(主席树) 题解 P3834 [[模板]可持久化线段树 2(主席树)] 1)静态求第k大数 可持久化线段树,不能用堆的方法存子结点了,所以用指针l表示左儿子r表示 ...

  2. 可持久化线段树——主席树

    前言: 最近心(po)血(yu)来(ya)潮(li)学习了一下主席树.(再不学就落伍了) 主席树,即可持久化线段树,支持维护和查询区间的第\(k\)大(小).区间不同种类个数等,基于线段树的思想之上 ...

  3. 【模板】可持久化线段树 1(主席树)

    题目背景 这是个非常经典的主席树入门题--静态区间第K小 数据已经过加强,请使用主席树.同时请注意常数优化 题目描述 如题,给定N个正整数构成的序列,将对于指定的闭区间查询其区间内的第K小值. 输入输 ...

  4. 【用学校抄作业带你走进可持久化线段树(主席树)】可持久化线段树概念+全套模板+例题入门:[福利]可持久化线段树)

    我似乎很少写这种算法博客 可持久化线段树概念 概念介绍(类比帮助理解) 简单分析一下时间和空间复杂度(内容池) 模板 结构体变量 建树模板 单点修改模板 单点查询模板 区间修改模板(pushup) 区 ...

  5. P3834-【模板】可持久化线段树 1(主席树)

    正题 评测记录:https://www.luogu.org/recordnew/lists?uid=52918&pid=P3834 题意 给定一个长度为n的序列,有m个询问,求一个区间内的第k ...

  6. 主席树 - 可持久化线段树

    模板 P3834 [模板]可持久化线段树 2(主席树) 区间求第 \(k\) 大 模板代码 #include<bits/stdc++.h> using namespace std; #de ...

  7. 学习笔记:可持久化线段树(主席树):静态 + 动态

    学习笔记:可持久化线段树(主席树):静态 + 动态 前置知识: 线段树.线段树分享可以看:@秦淮岸.@ZYzzz.@妄想の岚がそこに 树状数组.\(BIT\)分享可以看:@T-Sherlock.Chi ...

  8. 牛客网 暑期ACM多校训练营(第一场)J.Different Integers-区间两侧不同数字的个数-离线树状数组 or 可持久化线段树(主席树)...

    J.Different Integers 题意就是给你l,r,问你在区间两侧的[1,l]和[r,n]中,不同数的个数. 两种思路: 1.将数组长度扩大两倍,for(int i=n+1;i<=2* ...

  9. SP10628 COT - Count on a tree (树剖+可持久化线段树)

    题意: 给定一个包含 N 个结点的树. 树节点从 1 到 N编号..每个节点有一个整数权值. 我们会要求您执行以下操作: u v k : 询问从节点 u 到 节点 v 的路径上的第k小的权值 输入 在 ...

最新文章

  1. C++的error C2668: 'pow' : ambiguous call to overloaded function错误原因及解决方法
  2. 更新部分字段 NHibernate
  3. POJ - 3250 Bad Hair Day(单调队列/单调栈)
  4. i18n php_PHP国际化多语言的实现(非I18N)
  5. jquery中的 jquery.contains(a,b)
  6. Spring Boot 页面国际化
  7. HoloView -- Tabular Datasets
  8. 【C++】 C++入门和基础
  9. Arcgis desktop 9.3的破解方法(转载GIS帝国)
  10. php公文流转管理系统,OA办公系统公文流转
  11. 页面打印不全怎么办html css,win7打印网页显示不全怎么办|win7设置网页打印页面的方法...
  12. MSDB数据库置疑状态的解决方法
  13. css实现tab切换时下划线动画效果
  14. linux下文件的total是啥,linux中,ls -l命令显示的total的含义。
  15. java doc转换docx_JAVA - 将doc文档转为docx文档
  16. 如何找到算法的时间复杂度
  17. [Go]获取当前时间戳秒/毫秒/纳秒 转成字符串string
  18. 自用推荐,heic格式转换工具
  19. 对于微信支付宝支付的总结
  20. 数学方面的一些思维训练

热门文章

  1. Chrome网页截屏
  2. java实现调用打印机代码
  3. 史上最清晰的三路快速排序
  4. Halcon OCV检测
  5. 硬件知识收集总结---20210811
  6. window.open一个新网页显示,已拦截此网页上的弹出式窗口
  7. php切割音频文件,我想将一段录音中部分剪出来, 如何剪辑(截取)音频文件
  8. 安装MPlayer播放器(号称Linux中的万能播放器)
  9. pyqt5 绘图paintEvent
  10. 【RAC】 RAC For W2K8R2 安装--grid的安装(四)