【POJ2104】K-th Number(主席树)
题意:有n个数组成的序列,要求维护数据结构支持在线的下列两种操作:
1:单点修改,将第x个数修改成y
2:区间查询,询问从第x个数到第y个之间第K大的数
n<=100000,a[i]<=10^9
思路:一年前写过的第一道主席树,现在有了更深的理解
最朴素的想法是设t[i,j]为i时刻[1..j]的个数之和
询问时区间(x,y)时只需取出t[y]-t[x-1]这棵线段树,在其中二分查找即可
那么问题来了:这样的写法空间复杂度是O(n2)级别的,且每次更改只有logn个点会被更改
有很多一模一样的线段树中的节点是重复的,如何利用它们
充分利用历史版本,使用类似链表的方法将它们链接
比如只有左儿子被修改的节点就只新开左儿子,右儿子链到上一个时刻的右儿子即可
单点修改的时间和空间复杂度都是O(NlogN)
var t:array[..]of record
l,r,s:longint;
end;
a,b,c,d,root:array[..]of longint;
n,m,i,x,y,k,cnt:longint; procedure swap(var x,y:longint);
var t:longint;
begin
t:=x; x:=y; y:=t;
end; procedure qsort(l,r:longint);
var i,j,mid:longint;
begin
i:=l; j:=r; mid:=a[(l+r)>>];
repeat
while mid>a[i] do inc(i);
while mid<a[j] do dec(j);
if i<=j then
begin
swap(a[i],a[j]);
swap(c[i],c[j]);
inc(i); dec(j);
end;
until i>j;
if l<j then qsort(l,j);
if i<r then qsort(i,r);
end; procedure update(l,r:longint;var p:longint;x:longint);
var mid:longint;
begin
inc(cnt);
t[cnt]:=t[p];
p:=cnt;
inc(t[p].s);
if l=r then exit;
mid:=(l+r)>>;
if x<=mid then update(l,mid,t[p].l,x)
else update(mid+,r,t[p].r,x);
end; function query(p1,p2,l,r,k:longint):longint;
var mid,tmp:longint;
begin
if l=r then exit(l);
tmp:=t[t[p2].l].s-t[t[p1].l].s;
mid:=(l+r)>>;
if tmp>=k then exit(query(t[p1].l,t[p2].l,l,mid,k))
else exit(query(t[p1].r,t[p2].r,mid+,r,k-tmp));
end; begin
assign(input,'poj2104.in'); reset(input);
assign(output,'poj2104.out'); rewrite(output);
readln(n,m);
for i:= to n do
begin
read(a[i]); b[i]:=a[i]; c[i]:=i;
end;
qsort(,n);
d[c[]]:=;
for i:= to n do
if a[i]<>a[i-] then d[c[i]]:=d[c[i-]]+
else d[c[i]]:=d[c[i-]];
for i:= to n do
begin
root[i]:=root[i-];
update(,n,root[i],d[i]);
end;
for i:= to m do
begin
readln(x,y,k);
writeln(a[query(root[x-],root[y],,n,k)]);
end;
close(input);
close(output);
end.
UPD(2018.9.19):C++
//无修改区间第K小值
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef vector<int> VI;
#define fi first
#define se second
#define MP make_pair
#define N 210000
#define MOD 1000000007
#define eps 1e-8
#define pi acos(-1)
#define oo 1e9 struct arr
{
int l,r,s;
}t[];
int a[N],b[N],c[N],root[N],cnt,n; int read()
{
int v=,f=;
char c=getchar();
while(c<||<c) {if(c=='-') f=-; c=getchar();}
while(<=c&&c<=) v=(v<<)+v+v+c-,c=getchar();
return v*f;
} int Discrete(int x)
{
int l=;
int r=n;
while(l<=r)
{
int mid=(l+r)>>;
if(b[mid]==x) return c[mid];
if(b[mid]<x) l=mid+;
else r=mid-;
}
} void update(int l,int r,int x,int &p)
{
t[++cnt].l=t[p].l;
t[cnt].r=t[p].r;
t[cnt].s=t[p].s;
p=cnt;
t[p].s++;
if(l==r) return;
int mid=(l+r)>>;
if(x<=mid) update(l,mid,x,t[p].l);
else update(mid+,r,x,t[p].r);
} int query(int p1,int p2,int l,int r,int k)
{
if(l==r) return l;
int tmp=t[t[p2].l].s-t[t[p1].l].s;
int mid=(l+r)>>;
if(tmp>=k) return query(t[p1].l,t[p2].l,l,mid,k);
else return query(t[p1].r,t[p2].r,mid+,r,k-tmp);
} int main()
{
//freopen("poj2104.in","r",stdin);
//freopen("poj2104.out","w",stdout);
int m;
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++) scanf("%d",&a[i]);
for(int i=;i<=n;i++) b[i]=a[i];
sort(b+,b+n+);
c[]=;
for(int i=;i<=n;i++)
{
c[i]=c[i-];
if(b[i]!=b[i-]) c[i]++;
}
for(int i=;i<=n;i++) a[i]=Discrete(a[i]); //离散化
for(int i=;i<=n;i++)
{
root[i]=root[i-];
update(,n,a[i],root[i]);
}
for(int i=;i<=m;i++)
{
int x,y,k;
scanf("%d%d%d",&x,&y,&k);
int ans=b[query(root[x-],root[y],,n,k)];
printf("%d\n",ans);
} return ;
}
【POJ2104】K-th Number(主席树)的更多相关文章
- 【poj2104】K-th Number 主席树
题目描述 You are working for Macrohard company in data structures department. After failing your previou ...
- poj2104 k-th number 主席树入门讲解
poj2104 k-th number 主席树入门讲解 定义:主席树是一种可持久化的线段树 又叫函数式线段树 刚开始学是不是觉得很蒙逼啊 其实我也是 主席树说简单了 就是 保留你每一步操作完成之后 ...
- poj 2104 K-th Number 主席树+超级详细解释
poj 2104 K-th Number 主席树+超级详细解释 传送门:K-th Number 题目大意:给出一段数列,让你求[L,R]区间内第几大的数字! 在这里先介绍一下主席树! 如果想了解什么是 ...
- [POJ2104] K – th Number (可持久化线段树 主席树)
题目背景 这是个非常经典的主席树入门题--静态区间第K小 数据已经过加强,请使用主席树.同时请注意常数优化 题目描述 如题,给定N个正整数构成的序列,将对于指定的闭区间查询其区间内的第K小值. 输入输 ...
- poj2104 K-th Number区间第k小值 主席树
原来主席树就是可持久化线段树啊,刚知道,,, 作为一道裸题,还是必A的,然而一开始偷懒不写离散化跪了N多遍,后来在缪大的帮助下发现了这个问题,遂A之 ——又是这种破问题,实在不想说自己了 把n个数看成 ...
- 【POJ2104】【HDU2665】K-th Number 主席树
[POJ2104][HDU2665]K-th Number Description You are working for Macrohard company in data structures d ...
- POJ2104 K-th Number[主席树]【学习笔记】
K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 51440 Accepted: 17594 Ca ...
- [poj2104] K-th Number (主席树)
主席树 Description You are working for Macrohard company in data structures department. After failing y ...
- 主席树:POJ2104 K-th Number (主席树模板题)
K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 44952 Accepted: 14951 Ca ...
- POJ 2104 K-th Number 主席树(区间第k大)
题目链接: http://poj.org/problem?id=2104 K-th Number Time Limit: 20000MSMemory Limit: 65536K 问题描述 You ar ...
随机推荐
- linux更新git
在CentOS中使用yum install git安装的git是1.7版本的,所以需要更新1.9以及更高版本的git. 安装方法如下: 1.安装依赖的包: yum -y install curl-de ...
- js函数节流和函数防抖
概念解释 函数节流: 频繁触发,但只在特定的时间内才执行一次代码 函数防抖: 频繁触发,但只在特定的时间内没有触发执行条件才执行一次代码 函数节流 函数节流应用的实际场景,多数在监听页面元素滚动事件的 ...
- attachEvent和addEventListener 的使用方法和区别
attachEvent方法,为某一事件附加其它的处理事件.(不支持Mozilla系列)addEventListener方法 用于 Mozilla系列document.getElementById(&q ...
- Visual Studio 2017 UTF-8 无 BOM 一站式解决办法
问题背景:最近捡起C++,使用VS 2017平台.因为以前的编程习惯,喜欢使用UTF-8 无 BOM 的编码格式,好让自己的代码全球通用.但是VS 2017 对这个问题不是很友善.但最终找到了解决办法 ...
- 【结构型模式】《大话设计模式》——读后感 (12)在NBA我需要翻译?——适配器模式
适配器模式:将一个类的接口转换成客户希望的另外一个接口,Adapter模式使得原本由于接口不兼容而不能在一起工作的 那些类可以在一起工作了[DP] UML类图: 简单模拟一下代码: //已存在的.具有 ...
- Python基础-os模块 sys模块
sys模块 与操作系统交互的一个接口 文件夹相关 os.makedirs('dirname1/dirname2') 可生成多层递归目录 os.removedirs('dirname1') ...
- Django之FileField字段
头像上传 在头像上传的时候,属于文件类型 首先视图函数获取的时候,request.FILES.get('文件名变量') avatar_obj = request.FILES.get('avatar') ...
- leetcode-6-basic
解题思路: 这道题真实地反映了我今晚有多脑残=.=只需要从根号N开始向前找,第一个能被N整除的数就是width,然后存到结果就 可以了.因为离根号N越近,width越大,与length的差越小. ve ...
- CodeForce--Benches
A. Benches There are nn benches in the Berland Central park. It is known that aiai people are curr ...
- Linux inode 之我见
Linux硬盘组织方式为:引导区.超级块(superblock),索引结点(inode),数据块(datablock),目录块(diredtory block).其中超级块中包含了关于该硬盘或分区上的 ...