题意:有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(主席树)的更多相关文章

  1. 【poj2104】K-th Number 主席树

    题目描述 You are working for Macrohard company in data structures department. After failing your previou ...

  2. poj2104 k-th number 主席树入门讲解

    poj2104 k-th number 主席树入门讲解 定义:主席树是一种可持久化的线段树 又叫函数式线段树   刚开始学是不是觉得很蒙逼啊 其实我也是 主席树说简单了 就是 保留你每一步操作完成之后 ...

  3. poj 2104 K-th Number 主席树+超级详细解释

    poj 2104 K-th Number 主席树+超级详细解释 传送门:K-th Number 题目大意:给出一段数列,让你求[L,R]区间内第几大的数字! 在这里先介绍一下主席树! 如果想了解什么是 ...

  4. [POJ2104] K – th Number (可持久化线段树 主席树)

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

  5. poj2104 K-th Number区间第k小值 主席树

    原来主席树就是可持久化线段树啊,刚知道,,, 作为一道裸题,还是必A的,然而一开始偷懒不写离散化跪了N多遍,后来在缪大的帮助下发现了这个问题,遂A之 ——又是这种破问题,实在不想说自己了 把n个数看成 ...

  6. 【POJ2104】【HDU2665】K-th Number 主席树

    [POJ2104][HDU2665]K-th Number Description You are working for Macrohard company in data structures d ...

  7. POJ2104 K-th Number[主席树]【学习笔记】

    K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 51440   Accepted: 17594 Ca ...

  8. [poj2104] K-th Number (主席树)

    主席树 Description You are working for Macrohard company in data structures department. After failing y ...

  9. 主席树:POJ2104 K-th Number (主席树模板题)

    K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 44952   Accepted: 14951 Ca ...

  10. POJ 2104 K-th Number 主席树(区间第k大)

    题目链接: http://poj.org/problem?id=2104 K-th Number Time Limit: 20000MSMemory Limit: 65536K 问题描述 You ar ...

随机推荐

  1. 数组char a[4] 保存了一个数据,怎么转换为unsigned int呢 ?

    [待解决问题] 浏览: 701次 注意char并不表示字符的 a[0]=0; a[1]=0; a[2]=3; a[3]=0; 那么我要的unsigned int b应该等于: b= 0x0000030 ...

  2. Tcl/Cmds

  3. zookeeper伪集群(一)

    Zookeeper的安装和配置十分简单, 既可以配置成单机模式, 也可以配置成伪集群模式.集群模式. 本人将对伪集群.集群进行重点介绍: 铺垫: 1.集群必须是奇数(2N+1),伪集群和集群一致. 2 ...

  4. 我的Python分析成长之路6

    模块:本质就是.py结尾的文件.从逻辑上组织python代码. 包: 本质就是一个目录,带有__init__.py文件,从逻辑上组织模块. 模块的分类: 1.标准库(内置的模块) 2.开源库(第三方库 ...

  5. Python 使用multiprocessing 特别耗内存

    采用multiprocessing多进程进行数据计算的时候内存飚升,这总体可以说是multiprocessing的一个「bug」导致: 大致原因如下: multiprocessing.Process ...

  6. python的标准模块

    本文用于记录python中的标准模块,随时更新. decimal模块(解决小数循环问题): >>> import decimal >>> a = decimal.D ...

  7. Centos7 开机显示 ERST: Failed to get Error Log Address Range” 导致无法开机解决方法

    开机显示 ERST: Failed to get Error Log Address Range”   导致无法开机,也无法重新安装系统,解决方法:开机进入BIOS , 关闭ACPI选项即可正常开机

  8. xcode各个版本下载 xcode7 xcode6 xcode5

    登录开发者帐号,选择 support,然后操作如下图: 登录开发者帐号,选择 support,然后操作如下图: 登录开发者帐号,选择 support,然后操作如下图: 登录开发者帐号,选择 suppo ...

  9. 用asp.net+Jquery+Ajax+sqlserver编写的 (英语六级记单词)

    开始(英语对程序员的重要性引用) 出处 英语的重要性已经毋庸置疑,对于程序员来说更甚,一些最新的技术资料是英文的,如果想进入外企英语也是一个很重要的条件.对于程序员来说怎样学习好英语,在此谈一下我的一 ...

  10. PHP函数参数传递(相对于C++的值传递和引用传递)

    学语言学得比较多了,今天突然想PHP函数传递,对于简单类型(基本变量类型)和复杂类型(类)在函数参数传递时,有没有区别呢,今天测试了下: 代码如下: <?php function test($a ...