POJ2104 区间第k大(带修改)

学习笔记: 进阶版树状数组(区间修改区间查询以及查询第K大元素) 导 树状数组相信大家都很熟悉了,而今天我将会为大家带了一些更加全面的操作,并且欢迎补充哦。 其实我想说的是,除了RMQ,线段树能做的,树状数组都能做。 换句话说,这是一个稍微进阶版的的树状数组,读者至少要会单调修改区间查询这个最基本的操作。 树状数组应该算是常数非常小的数据结构啦。而小生特别喜欢这个数据结构,这是因为它特别短,就是又短又快! 核心操作:lowbit int ... 阅读详情

Description

  给定一个长度为N的已知序列A[i](1<=i<=N),要求维护这个序列,能够支持以下两种操作:
  1、查询A[i],A[i+1],A[i+2],…,A[j](1<=i<=j<=N)中,升序排列后排名第k的数。
  2、修改A[i]的值为j。
  所谓排名第k,指一些数按照升序排列后,第k位的数。例如序列{6,1,9,6,6},排名第3的数是6,排名第5的数是9。

Input

  输入文件的第一行包含两个整数N和M,分别表示序列的长度为N和有M个操作。
  接下来的N个不大于10^9正整数,第i个表示序列A[i]的初始值。
  然后的M行,每行为一个操作Q i j k 或者C i j分别表示查询A[i],A[i+1],A[i+2],…,A[j](1<=i<=j<=N)中,升序排列后排名第k的数和修改A[i]的值为j。

Output

  对于每个查询,输出一行整数,为查询的结果。测试数据之间不应有空行。

Sample Input

5 3 3 2 1 4 7 Q 1 4 3 C 2 6 Q 2 5 3

Sample Output

3 6

Hint

【数据范围】:
  20%的数据中,m,n≤100; 
  40%的数据中,m,n≤1000; 
  100%的数据中,m,n≤10000。

打一发树套树,表示splay的哪个旋转到根下面的写法好迷。。

树套树常数贼大= =主席树貌似好用不少(还没复习233)

#include<bits/stdc++.h>
using namespace std;
#define Inc(i,L,r) for(register int i=(L);i<=(r);++i)
#define Red(i,r,L) for(register int i=(r);i>=(L);--i)
const int N = 1e4+10,Maxsiz = N*log2(N)*2;
int n,m,a[N];
struct Splay{
	int p[Maxsiz],ch[Maxsiz][2];
	int cnt,k[Maxsiz],siz[Maxsiz];
	#define Ls(v) ch[v][0]
	#define rs(v) ch[v][1]
	#define sum(v) siz[v]=siz[Ls(v)]+siz[rs(v)]+1
	inline void rotate(int x){
		int f=p[x],gf=p[f],tp=rs(f)==x,son=ch[x][!tp];
		ch[p[son]=f][tp]=son,sum(f);
		ch[p[f]=x][!tp]=f,sum(x);
		ch[p[x]=gf][rs(gf)==f]=x;
	}
	inline void splay(int x,int &rt){
		while(p[x]){
			if((p[p[x]])&&((rs(p[p[x]])==p[x])==(rs(p[x])==x)))rotate(p[x]);
			rotate(x);
		}
		rt=x;
	}
	inline void newnode(int x,int v,int Fa){
		siz[x]=1;
		p[x]=Fa;
		k[x]=v;
	}
	inline void insert(int &x,int v,int Fa,int &root){
		if(!x)return newnode(x=++cnt,v,Fa),splay(x,root),void();
		insert(ch[x][k[x]<v],v,x,root);
	}
	inline int Query(int x,int v){
		int tot=0;
		while(x)k[x]<=v?tot+=siz[Ls(x)]+1,x=rs(x):x=Ls(x);
		return tot;
	}
	inline int findpre(int x){
		for(x=Ls(x);rs(x);x=rs(x));
		return x;
	}
	inline int findsub(int x){
		for(x=rs(x);Ls(x);x=Ls(x));
		return x;
	}
	inline void delet(int x,int v,int &root){
		for(;k[x]^v;x=ch[x][k[x]<v]);
		splay(x,root);
		if(!Ls(x))return p[root=rs(x)]=0,void();
		int pre=findpre(x);
		splay(pre,root);
		rs(pre)=rs(x);
		if(rs(x))p[rs(x)]=pre;
		sum(pre);
	}
}sp;
struct SegMent{
	struct tree{
		int L,r,rt;
	}t[N<<2];
	#define Lc v<<1
	#define rc v<<1|1
	inline void Modify(int v,int x,bool cmd){
		if(t[v].L>x||t[v].r<x)return ;
		cmd?sp.insert(t[v].rt,a[x],0,t[v].rt):sp.delet(t[v].rt,a[x],t[v].rt);
		if(t[v].L==t[v].r)return ;
		Modify(Lc,x,cmd),Modify(rc,x,cmd);
	}
	inline int Query(int v,int A,int b,int k){
		if(t[v].L>b||t[v].r<A)return 0;
		if(A<=t[v].L&&t[v].r<=b)return sp.Query(t[v].rt,k);
		return Query(Lc,A,b,k)+Query(rc,A,b,k);
	}
	inline void build(int v,int L,int r){
		t[v]=(tree){L,r};
		Inc(i,L,r)sp.insert(t[v].rt,a[i],0,t[v].rt);
		if(L==r)return ;
		int Mid=L+r>>1;
		build(Lc,L,Mid),build(rc,Mid+1,r);
	}
}tr;
inline void init(){
	scanf("%d%d",&n,&m);
	Inc(i,1,n)scanf("%d",&a[i]);
	tr.build(1,1,n);
}
inline void Modify(){
	int x,k;scanf("%d%d",&x,&k);
	tr.Modify(1,x,0);
	a[x]=k;
	tr.Modify(1,x,1);
}
inline void Query(){
	int ans,L,r,kth;
	scanf("%d%d%d",&L,&r,&kth);
	for(int x=tr.t[1].rt;x;){
		int tmp=tr.Query(1,L,r,sp.k[x]);
		if(tmp<kth)x=sp.rs(x);
		else ans=sp.k[x],x=sp.Ls(x);
	}
	cout<<ans<<"\n";
}
inline void solv(){
	Inc(i,1,m){
		char c=getchar();while((c^'Q')&&(c^'C'))c=getchar();
		c=='Q'?Query():Modify();
	}
}
int main(){
	init();
	solv();
	return 0;
}

补一个主席树,,

和静态版本略有不同(我感觉完全不一样。。),说的可能有点乱,大概是那个意思。

查询区间[l,r],由于主席树的前缀和性质想到树状数组,常规的树状数组直接改点值,我们不过是把点值换成了整棵线段树。

简单地说,就是树状数组套上多棵动态开点的权值线段树。

但是这样写就不满足主席树只加点不删除的性质。。我也很迷~主席树的定义到底是个什么= =

再补:满足前缀和性质的线段树就是主席树~

#include<bits/stdc++.h>
using namespace std;
const int Maxn=10005;
int n,a[Maxn];
struct SegMent{
	struct tree{
		int ls,rs,siz;
	}t[Maxn*40];int cnt;
	inline void modify(int &x,int v,int l,int r,int cmd){
		if(l>v||r<v)return ;
		t[x?:x=++cnt].siz+=cmd;
		if(l==r)return ;
		int mid=l+r>>1;
		modify(t[x].ls,v,l,mid,cmd),modify(t[x].rs,v,mid+1,r,cmd);
	}
}seg;
struct BIT{
	int root[Maxn];
	int q[2][Maxn];
	#define lowbit(x) (x)&-(x)
	inline void update(int x,int k,int cmd){
		for(;x<=n;x+=lowbit(x))seg.modify(root[x],k,0,(1<<30),cmd);
	}
	inline void getroot(int l,int r){
		for(q[0][0]=0;l>0;l-=lowbit(l))q[0][++q[0][0]]=root[l];
		for(q[1][0]=0;r>0;r-=lowbit(r))q[1][++q[1][0]]=root[r];		
	}
	inline int sum(bool t){
		int ret=0;
		for(int i=1;i<=q[t][0];++i)ret+=seg.t[seg.t[q[t][i]].ls].siz;
		return ret;
	}
	inline int query(int l,int r,int k){
		if(l==r)return l;
		int size=sum(1)-sum(0);
		int mid=l+r>>1;
		if(size>=k){
			for(int i=1;i<=q[0][0];++i)q[0][i]=seg.t[q[0][i]].ls;
			for(int i=1;i<=q[1][0];++i)q[1][i]=seg.t[q[1][i]].ls;
			return query(l,mid,k);
		}else {
			for(int i=1;i<=q[0][0];++i)q[0][i]=seg.t[q[0][i]].rs;
			for(int i=1;i<=q[1][0];++i)q[1][i]=seg.t[q[1][i]].rs;
			return query(mid+1,r,k-size);
		}
	}
}bit;
int main(){
	int m;scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)scanf("%d",&a[i]);
	for(int i=1;i<=n;++i)bit.update(i,a[i],1);
	for(int i=1;i<=m;++i){
		char c=getchar();while(!isalpha(c))c=getchar();
		if(c=='C'){
			int x,k;scanf("%d%d",&x,&k);
			bit.update(x,a[x],-1);
			bit.update(x,a[x]=k,1);
		}else {
			int l,r,k;scanf("%d%d%d",&l,&r,&k);
			bit.getroot(l-1,r);
			printf("%d\n",bit.query(0,(1<<30),k));
		}
	}
	return 0;
}

 

区间第K值带修改 分块 区间第K值带修改 Q:给定一个序列 1、查询一个L到R的区间内的第K大(小)值。2、修改一个值。 这道神题困扰了我很久,直到学了各种各样的算法才会会这道题。 先比较一下流行的算法的效率吧 对于一个长度为N的序列 暴力:对于一段查询区间每次进行快排。 时间复杂度: 单次查询:O(NlogN) 修改:O(1) 空间复杂度:O(N) 线段树套平衡树: 单次查询:O(log^3 N) 阅读详情

相关推荐

区间修改、区间查询

区间修改、区间查询

11 323

区间元素可变(添加与删除)的第求k大数和给定数的排名问题

思想来源于张昆玮的《统计的力量》 划分树只能在静态区间上求第k大数和给定数的排名 基于字母数的动态性和数值大小的字典有序性,只要在其结点上存以当前节点结尾的串(数的二进制形式)的数目,和以该串为前缀的串的数目,便可在位模式长度时间内进行元素增添、删除和以上问题的求解。但当元素数值过大,可能出现时间常数过大的问题,并且空间需求不易估计。

qwe20060514的专栏 778

高频面试题-项目介绍篇

聊聊如何介绍项目经历。

m0_73359763的博客 1908

区间第k大的几种解法

区间第K大问题,变化包括带修改和不带修改,强制在线和允许离线 修改主要是单点修改,我们前面也只讨论这种情况。 接下来我们从编程复杂度和时空复杂度来讨论几种做法。 1.整体二分(编程复杂度:低-中,时间复杂度:优秀,空间复杂度:优秀) 缺点:只能做离线 优点:空间都是O(n)。常数小。带修改O(nlog2n),不带修改O(nlogn)。 但是不带修改的情况,如果允许的话,...

weixin_30564785的博客 728

【OpenCV】手眼标定实战:从原理到calibrateHandEye的完整实现

本文详细解析了机器人视觉中的手眼标定原理与实战,重点介绍了如何使用OpenCV的calibrateHandEye函数实现从数据采集到结果验证的完整流程。文章深入剖析了AX=XB核心方程,区分了眼在手上与眼在手外两种配置,并提供了详细的代码示例与避坑指南,帮助开发者精准建立相机与机械臂末端的坐标转换关系,是机器人精准抓取的关键技术。

weixin_29046611的博客 508

整合Springboot+MybatisPlus+达梦数据库

整合Springboot+MybatisPlus+达梦数据库,以及一些坑

波波的博客 6677

【poj2104】不带修改的区间第k大 主席树

【题目大意】 给定一个长为N的序列,每个序列的权值为Ai.有M个询问,每个询问为(L,R,K),分别代表[L,R]的第K大的数。 期中n=100000,m=5000 【题解】 用主席树解决,那么什么是主席树呢? 首先我们先明确一下权值线段树的概念。 平常我们用的线段树都是区间线段树,而权值线段树和平衡树中树的结点意义是类似的。 权值线段树中(下文所说线段树均值权值线段树),每个结

chty_syq的博客 375

5分钟搞定单细胞marker基因气泡图:scDotPlot保姆级教程(含Seurat适配)

本文提供了一份详细的scDotPlot R包使用教程,帮助用户在5分钟内完成单细胞marker基因气泡图的绘制。教程涵盖环境准备、Seurat和SingleCellExperiment对象的适配处理、进阶可视化技巧及自动化报告生成,特别适合生物信息学新手和临床研究者快速掌握这一高效的可视化工具。

weixin_29047545的博客 261

[POJ 2104]K-th Number (不带修改的区间k大,函数式线段树)

/* http://hi.baidu.com/wyl8899/item/e00796a9cb2df73d020a4d68 */ #include #include #include using namespace std; const int MAX_N=100005; const int MAX_M=5005; const int MAX=MAX_M*600; int n,m; int

Yukar_syt的专栏 910

Python 爬虫实战:拼多多商品评论情感分析(含词云生成与差评预警)

在电商行业竞争日益激烈的当下,商家对商品评论的分析需求愈发迫切。通过 Python 爬虫收集拼多多商品评论,并结合情感分析、词云可视化及差评预警技术,商家可精准洞察消费者反馈,优化商品与服务。本文将深度剖析从爬虫搭建到数据挖掘的关键环节,助力读者构建全流程电商评论分析系统。

yansideyucsdn的博客 1450

全面解读AI Infra:架构、生态与未来趋势

文章摘要 大模型时代下,AI基础设施(AI Infra)成为关键技术基建,涵盖从数据准备到模型服务的全栈技术体系。文章系统解构了AI Infra的四层架构(硬件资源层、资源管理调度层、开发框架层、平台工具层),并分析了全球AI Infra生态图谱,包括云计算巨头、芯片厂商等全栈服务商,以及中国特色的多元竞合格局。通过对比Data Infra与AI Infra的核心差异,指出AI Infra更关注智能应用的规模化与自动化。文章还探讨了从传统数据设施向AI基础设施的转型路径,强调自主可控、软硬协同等发展趋势,为

技术引领业务创新 610

POJ-2104 K-th Number (主席树 不带修改区间第k大)

主席树 入门题。题意:1e5个数,5e4次询问,每次询问区间第k大。

hmc0411的博客 534

人工智能训练师三级补贴3120元申领全攻略|条件+流程+五省市对比

补贴是真的,但不是"白给"的。你需要满足社保、户籍、时间等条件,严格按照流程操作。记住四件事先确认自己是否满足条件,再报名——别考完了才发现领不到紧缺工种补贴更高——确认你所在城市是否在紧缺目录中证书下发后12个月内申请——设个日历提醒材料准备齐全再提交——避免来回折腾如果你正在考虑考人工智能训练师三级证书,想要从报名到备考到拿证到申领补贴的完整一站式指南,欢迎查看我的付费专栏:📖《人工智能训练师三级·从零到拿证完全指南》80篇系统化内容,覆盖报名、备考、冲刺、拿证全流程。

白话机器学习 1521

区间第k大(poj 2104)

#include #include #include #include #define maxn 1000005 using namespace std; vector dat[maxn*2]; int num[maxn],A[maxn]; int build (int o,int L,int R){ if (L==R){ dat[o].push_back(num[L]);

LHYL 849

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

【poj2104】区间第k大(版本1)

【POJ2104】区间第k大 Description 给定一个长度为n的序列,m个询问,每个询问的形式为:L,r,k表示在[L,r]间中的第k大元素。 Input 第1行:2个数,n,m表示序列的长度和询问的个数 第2行:n个数,表示n个数的大小 第3-m+2行:每行3个数,L,r,k表示询问在[L,r]区间内第k小的元素

袋鼠与蒟蒻 440

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

区间第K大(POJ-2104)

可持久化线段树不是一颗完全二叉树,所以不能用层次序编号,而应该直接记录每个节点的左、右子节点的编号。可持久化线段树维护了每次操作后线段树的历史形态。 下面举个简单的例子来理解一下: 以poj-2104为例;这棵树是一颗不用修改的线段树 题意:即多次查询,查询区间第K大的数。 POJ-2104 (区间第k大) //主席树的学习--区间第k大 //区间第k大又可以用整体分治算法,归并树,线段树套平衡树...

小` pi孩 283

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

主席树-区间第k大值(不带修改)

题目:poj2104 && hdu2665 题意:求区间第K大的值。 分析:资料1  主席树包含n棵线段树,这n棵线段树的形状完全相同。而且树与树之间有很大的重叠。 线段树root[i]表示数组a中区间[1,i]的元素插进线段树时的版本。 那么再添加一个元素a[i+1]时,只需修改线段树上的从根节点开始向下走的一条路径。 那么对于线段树root[i+1],我们先“拷贝”线段树root[

w20810的专栏 2142

POJ 2104 K-th Number【整体二分 + 树状数组】

本来只是想学一下CDQ,还是先把整体二分搞懂一点。这题窝几个月前分别用划分树,树套树,主席树和挑战上介绍的分桶法实现了一发(然而现在都忘得差不多了) 最快的是划分树,其次是主席树,然后是树套树,还有一个10000+ms分桶法的思想实现的,最上面的就是整体二分的方法。题目链接:http://poj.org/problem?id=2104题意:给定序列,求每次询问区间的第K大数。分析:首先介绍整体

Tuesday 8105

poj 2104 可持久化线段树 区间K大 不修改

poj 2104 区间k大 不修改 只查询 模板 #include #include #include #include #include #include #include #define N 240008 #define M 5500000 using namespace std; int n,m,rt[N]; struct Node{ int l,r,cnt;; }t

我的博客 296

poj 2104 区间第k大 主席树

/* 静态主席树求区间第K大 poj 2104 主要思想: 1. 将数据离散化 2. 用线段树来维护信息,维护处于该区间的数的个数 3. 将原有数组中的每一个数依次插入,每次插入一个值的时候新建一棵线段树 这样就有了n+1棵线段树,对于询问(l,r,k),只需查询T[l-1]和T[r]两棵线段树

legedexinshi的专栏 573

POJ 2104 可持久化线段树 求区间第k大

K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 35455   Accepted: 11296 Case Time Limit: 2000MS Description You are working for Macrohard com

_rabbit的专栏 1408

【划分树】求区间K大数

<br />       求区间K大数,众所周知有二分答案+树套树的做法,每个询问复杂度为O(log3N),可谓近似一个O(N)了,不仅时间复杂度高,编程复杂度也不低,后来才发现还有一种叫划分树的数据结构,专门做这种问题。<br />      本来觉得知道个树套树就够了,据我所知划分树还不支持区间修改操作,但是这次NOI一试的piano偏偏那出题人就有这么重口味,给你来两个500000的点!真是不简单,当时我都在想有没有O(N)的算法了。树套树的复杂度偏偏就被卡掉了,三个点平均每个点要跑5秒,好吧,那就学

Evil.livE 4382

整体二分初探 两类区间第K大问题 poj2104 & hdu5412

看到好多讲解都把整体二分和$CDQ$分治放到一起讲 不过自己目前还没学会$CDQ$分治 就单独谈谈整体二分好了 先推荐一下$XHR$的 <浅谈数据结构题的几个非经典解法> 整体二分在当中有较为详细的讲解 先来说一下静态第$K$小的整体二分解法 $(POJ2104)$ 题目链接:http://poj.org/problem?id=2104 所谓整体二分 就是利用所有的询问相...

weixin_30621919的博客 141

POJ2104 K-th Number —— 区间第k小 整体二分

题目链接:https://vjudge.net/problem/POJ-2104 K-th Number Time Limit:20000MS Memory Limit:65536K Total Submissions:64110 Accepted:22556 Case Time Limit:2000MS ...

alince20008的博客 111

整体二分求区间第k大模板(POJ 2104)

自己的模板,线段树实现的,可以参考一下 算法步骤 参考一下文章 http://www.cnblogs.com/dirge/articles/5810855.html https://www.cnblogs.com/rayrayrainrain/articles/6477611.html //#include<bits/stdc++.h> #include&l...

Bowen的博客 551
上一篇: USACO 2009 January Gold 安全路径
下一篇: BZOJ3196 二逼平衡树
DancingZ
博客等级 码龄9年 10粉丝 137原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值