【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 ...
随机推荐
- SSH程序框架之Spring与HIbernate整合
spring整合hibernate 有两种方式 1.注解方式 2.xml方式实现 Spring整合Hibernate有什么好处? 1.由IOC容器来管理Hibernate的SessionFactory ...
- 简单的C++ DLL注入
今天呢,我们来讨论一下用C++实现DLL注入的简单方法. 环境: Visual Studio 2015及以上 Windows 7及以上 入门需要了解的: DLL是什么:DLL_360百科 DLL是Dy ...
- MySQL的GTID复制与传统复制的相互切换
MySQL的GTID复制与传统复制的相互转换 1. GTID复制转换成传统复制 1.1 环境准备 1.2 停止slave 1.3 查看当前主从状态 1.4 change master 1.5 启动主从 ...
- python入门:输出1-100之内的所有奇数和偶数
#!/usr/bin/env python # -*- coding:utf-8 -*- #输出1-100之内的所有奇数和偶数 """ 给start赋值等于1,while ...
- Linux 用户管理(一)
一.基础知识介绍 用户 用户组的概念 每个文件和进程,都需要对应一个用户和用户组 linux 系统通过UID和 GID识别用户和组 用户名相当于人名(给人看) UID和GID相当于身份证(系统用的) ...
- Python模块(二)(序列化)
1. namedtuple 命名元组->类似创建了一个类 from collections import namedtuple p = namedtuple("Point", ...
- LeetCode(304)Range Sum Query 2D - Immutable
题目 Given a 2D matrix matrix, find the sum of the elements inside the rectangle defined by its upper ...
- 【HIHOCODER 1055】 刷油漆(树上背包)
描述 小Ho有着一棵灰常好玩的树玩具!这棵树玩具是由N个小球和N-1根木棍拼凑而成,这N个小球都被小Ho标上了不同的数字,并且这些数字都是处于1..N的范围之内,每根木棍都连接着两个不同的小球,并且保 ...
- HDU - 4763 Theme Section (KMP的next数组的应用)
给定一个字符串,求出一个前缀A,使得字符串的构成可以表示成ABABA的形式(B可以为空串). 输出这个前缀的最大长度. KMP算法Next数组的使用. 枚举中间的每个位置,可以根据Next数组求出这个 ...
- c++,友元类和友元函数
都是声明时友元的东西可以访问自己类的私有和保护成员 类的友元 友元是C++提供的一种破坏数据封装和数据隐藏的机制. 通过将一个模块声明为另一个模块的友元,一个模块能够引用到另一个模块中本是被隐藏的信息 ...