P5494-[模板]线段树分裂
正题
题目链接:https://www.luogu.com.cn/problem/P5494
题目大意
给出一个可重集合要求支持
- 将集合\(p\)中在\([l,r]\)的数放到一个新的集合中
- 将集合\(t\)的所有数放入集合\(p\)中
- 在集合\(p\)中放入\(x\)个\(p\)
- 查询集合\(p\)中在\([l,r]\)区间的数
- 查询集合\(p\)中第\(k\)小的数
\(1\leq n,m\leq 2\times 10^5\)
解题思路
考虑怎么分裂,就照着一个位置\(pos\)做下去顺路一直开新节点,往左走时把右节点给新的节点就好了。
然后分裂两次再把左右合并就好了。
时间复杂度\(O(n\log n)\)
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=2e5+10,M=N<<5;
ll n,m,tot,rt[N];
ll cnt,w[M],ls[M],rs[M];
void Change(ll &x,ll L,ll R,ll pos,ll val){
if(!x)x=++cnt;
if(L==R){w[x]+=val;return;}
ll mid=(L+R)>>1;
if(pos<=mid)Change(ls[x],L,mid,pos,val);
else Change(rs[x],mid+1,R,pos,val);
w[x]=w[ls[x]]+w[rs[x]];return;
}
ll Ask(ll x,ll L,ll R,ll l,ll r){
if(!x)return 0;
if(L==l&&R==r){return w[x];}
ll mid=(L+R)>>1;
if(r<=mid)return Ask(ls[x],L,mid,l,r);
if(l>mid)return Ask(rs[x],mid+1,R,l,r);
return Ask(ls[x],L,mid,l,mid)+Ask(rs[x],mid+1,R,mid+1,r);
}
ll Bsk(ll x,ll L,ll R,ll k){
if(L==R)return L;
ll mid=(L+R)>>1;
if(w[ls[x]]>=k)return Bsk(ls[x],L,mid,k);
return Bsk(rs[x],mid+1,R,k-w[ls[x]]);
}
ll Merge(ll x,ll y){
if(!x||!y)return x+y;
ls[x]=Merge(ls[x],ls[y]);
rs[x]=Merge(rs[x],rs[y]);
w[x]=w[x]+w[y];
return x;
}
ll Split(ll x,ll L,ll R,ll pos){
if(!x)return 0;
ll y=++cnt,mid=(L+R)>>1;
if(L==R)return y;
if(pos<=mid)swap(rs[x],rs[y]);
if(L==R)return y;
if(pos<=mid)ls[y]=Split(ls[x],L,mid,pos);
else rs[y]=Split(rs[x],mid+1,R,pos);
w[x]=w[ls[x]]+w[rs[x]];w[y]=w[ls[y]]+w[rs[y]];
return y;
}
signed main()
{
scanf("%lld%lld",&n,&m);tot=1;
for(ll i=1;i<=n;i++){
ll x;scanf("%lld",&x);
if(x)Change(rt[1],0,n,i,x);
}
while(m--){
ll op;scanf("%lld",&op);
if(op==0){
ll p,x,y;scanf("%lld%lld%lld",&p,&x,&y);
++tot;rt[tot]=rt[p];
rt[p]=Split(rt[p],0,n,x-1);
rt[tot]=Merge(rt[tot],Split(rt[p],0,n,y));
swap(rt[p],rt[tot]);
}
else if(op==1){
ll p,t;scanf("%lld%lld",&p,&t);
rt[p]=Merge(rt[p],rt[t]);
}
else if(op==2){
ll p,x,q;scanf("%lld%lld%lld",&p,&x,&q);
Change(rt[p],0,n,q,x);
}
else if(op==3){
ll p,x,y;scanf("%lld%lld%lld",&p,&x,&y);
printf("%lld\n",Ask(rt[p],0,n,x,y));
}
else if(op==4){
ll p,k;scanf("%lld%lld",&p,&k);
if(w[rt[p]]<k){puts("-1");continue;}
printf("%lld\n",Bsk(rt[p],0,n,k));
}
}
return 0;
}
P5494-[模板]线段树分裂的更多相关文章
- 「Luogu P5494 【模板】线段树分裂」
(因为没有认证,所以这道题就由Froggy上传) 线段树分裂用到的地方确实并不多,luogu上以前也没有这道模板题,所以就出了一道,实在是想不出怎么出模板了,所以这道题可能可以用一些其他的算法水过去. ...
- 有趣的线段树模板合集(线段树,最短/长路,单调栈,线段树合并,线段树分裂,树上差分,Tarjan-LCA,势能线段树,李超线段树)
线段树分裂 以某个键值为中点将线段树分裂成左右两部分,应该类似Treap的分裂吧(我菜不会Treap).一般应用于区间排序. 方法很简单,就是把分裂之后的两棵树的重复的\(\log\)个节点新建出来, ...
- hdu 1754 I Hate It (模板线段树)
http://acm.hdu.edu.cn/showproblem.php?pid=1754 I Hate It Time Limit: 9000/3000 MS (Java/Others) M ...
- 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)
To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...
- [BZOJ4552][TJOI2016&&HEOI2016]排序(二分答案+线段树/线段树分裂与合并)
解法一:二分答案+线段树 首先我们知道,对于一个01序列排序,用线段树维护的话可以做到单次排序复杂度仅为log级别. 这道题只有一个询问,所以离线没有意义,而一个询问让我们很自然的想到二分答案.先二分 ...
- [HEOI2016/TJOI2016] 排序 解题报告(二分答案/线段树分裂合并+set)
题目链接: https://www.luogu.org/problemnew/show/P2824 题目描述: 在2016年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在 ...
- luoguP2824 [HEOI2016/TJOI2016]排序(线段树分裂做法)
题意 所谓线段树分裂其实是本题的在线做法. 考虑如果我们有一个已经排好序的区间的权值线段树,那么就可以通过线段树上二分的方法得到第\(k\)个数是谁. 于是用set维护每个升序/降序区间的左右端点以及 ...
- BZOJ4552 HEOI2016/TJOI2016排序(线段树合并+线段树分裂)
很久以前写过二分答案离线的做法,比较好理解.事实上这还是一个线段树合并+分裂的板子题,相比离线做法以更优的复杂度做了更多的事情.具体不说了.怎么交了一遍luogu上就跑第一了啊 #include< ...
- hdu3966 树链剖分点权模板+线段树区间更新/树状数组区间更新单点查询
点权树的模板题,另外发现树状数组也是可以区间更新的.. 注意在对链进行操作时方向不要搞错 线段树版本 #include<bits/stdc++.h> using namespace std ...
- 【线段树】【P3372】模板-线段树
百度百科 Definition&Solution 线段树是一种log级别的树形结构,可以处理区间修改以及区间查询问题.期望情况下,复杂度为O(nlogn). 核心思想见百度百科,线段树即将每个 ...
随机推荐
- Specification使用in
//是否包含下级授权点 1 包含 2 不包含 List<AuthorizationPoint> authList = null; List<Long> pointIdList ...
- 使用JS获取SessionStorage的值
参考:https://www.jb51.net/article/132729.htm 获取sessionStorage的意义 首先获取它是为了将获得的信息输出或者alert():让人容易看到, 其次, ...
- WPF简易聊天室
一.聊天界面如下
- Spark入门:Spark运行架构(Python版)
此文为个人学习笔记如需系统学习请访问http://dblab.xmu.edu.cn/blog/1709-2/ 基本概念 * RDD:是弹性分布式数据集(Resilient Distributed ...
- input text 只能输入数字 js 正则表达式
$("#txt1").keyup(function () { $(this).val($(this).val().replace(/[^0-9.]/g, '')); }).bind ...
- Java抽象类(abstract)
抽象类和接口 一.抽象类 1.什么是抽象类? 类和类之间具有共同的特征,将这些特征提取出来,形成的就是抽象类. 类到对象是实例化,对象到类是抽象. 抽象类和具体类是相对的概念."抽象&quo ...
- ES6扩展——函数扩展之剩余函数
1.结合扩展运算符 //剩余参数是做聚合的,扩展运算符是做展开的 function sum(...args){ console.log(arguments); console.log(argument ...
- docker开启remote-api 2375端口后,Failed to start Docker Application Container Engine,重启docker失败的问题解决
1. 按照网上的教程修改了 /usr/lib/systemd/system/docerk.service配置后,重启失败.修改/etc/docker/daemon.json 增加hosts后重启也是 ...
- Nginx版本平滑升级方案
背景:由于负载均衡测试服务器中nginx版本过低,存在安全漏洞,查询相关修复漏洞资料,需要采取nginx版本升级形式对漏洞进行修复. Nginx平滑升级方案 1.案例采用版本介绍 旧版本 nginx- ...
- Linux复习笔记-001-进程的管理
1.什么是进程? 进程是已经启动的可执行的程序运行实例. 程序是二进制文件,静态 ./bin/date/ /usr/sbin/ 进程:是程序运行的过程 2.Linux为1的进程? centos5或6为 ...