POJ2104 K-th Number——划分树——pku2104

本文详细介绍了划分树的概念、工作原理以及如何通过代码实现求解无更改情况下区间第k小值的问题。通过实例分析,读者可以深入理解划分树在排序基础上的分治思想,并学会构建和使用该数据结构解决特定类型的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

按照铎铎大牛的AC Record做的第一题,就被虐得很惨。

这是划分树的模板题。划分树,主要是求无更改的情况下区间第k小值。建树和线段树有些类似,但是划分树是在排序的基础上,左子树记录比中间值小的值,右子树记录比中间值大的数,在每棵子树中不改变原数列中的顺序。

查找也类似线段树,规定查找区间,定义函数Find(code,l,r,kth,dep),code为当前查找到的节点值,l,r是区间左右界,为闭区间,dep代表当前查找的深度。如果l,r与code的管辖区间相同就返回b[l+kth-1](b为排好序的数列),否则令t1、t2为[tree[code].left,l-1]进入左子树的数的个数和[tree[code].left,r]进入左子树的个数。

如果t1-t2>=kth,就查找左子树,边界为[tree[code].left+tree[code].left+t2,tree[code].left+tree[code].left+t1-1]

(也就是[tree[code].left+[tree[code].left,l-1]区间进入左子树的数的个数,tree[code].left+[tree[code].left,r]进入左子树的数的个数]),

否则查找右子树,边界为[tree[code].mid+1+l-tree[code].left-t2,tree[code].mid+1+r-tree[code].left-t1]

(也就是[tree[code].mid+[tree[code].left,l-1]区间进入右子树的数的个数,tree[code].mid+[tree[code].left,r]进入右子树的数的个数])

 

有点繁琐,自己推导一下就行了。

 

代码:

Program poj2104;//By_Thispoet
Const 
	maxn=100005;
Var
	i,j,k,m,n,p,q,x,y,z				:Longint;
	g,rel							:Array[0..20,0..maxn]of Longint;
	b								:Array[1..maxn]of Longint;
	tree							:ARray[1..maxn*10]of record left,right,mid:Longint; end;
	
Procedure Qsort(l,r:Longint);
var i,j,k,temp:Longint;
begin
	i:=l;j:=r;k:=b[i+random(j-i+1)];
	repeat
		while b[i]<k do inc(i);
		while b[j]>k do dec(j);
		if i<=j then 
			begin
				temp:=b[i];b[i]:=b[j];b[j]:=temp;
				inc(i);dec(j);
			end;
	until i>j;
	if l<j then Qsort(l,j);
	if i<r then Qsort(i,r);
end;
	
	
Procedure Build_Tree(code,l,r,dep:Longint);
var i,j,k,ll,rr:Longint;
begin
	with tree[code] do 
		begin
			left:=l;right:=r;mid:=(l+r)>>1;
			if l=r then exit;
			ll:=l-1;rr:=mid;
			for i:=l to r do 
				begin
					if (g[dep-1,i]<=b[mid])and(ll<mid)then 
						begin
							inc(ll);
							g[dep,ll]:=g[dep-1,i];
							if l>i-1 then rel[dep,i]:=1 else rel[dep,i]:=rel[dep,i-1]+1;
						end else
							begin
								inc(rr);
								g[dep,rr]:=g[dep-1,i];
								if l>i-1 then rel[dep,i]:=0 else rel[dep,i]:=rel[dep,i-1];
							end;
				end;
			Build_Tree(code*2,l,mid,dep+1);
			Build_Tree(code*2+1,mid+1,r,dep+1);
		end;
end;
	
	
Function Find(code,l,r,k,dep:Longint):Longint;
var t1,t2,tnum,ll,rr:Longint;
begin
	if (tree[code].left=l)and(tree[code].right=r)then exit(b[l+k-1]);
	t1:=rel[dep,r];
	if tree[code].left>l-1 then t2:=0 else t2:=rel[dep,l-1];
	tnum:=t1-t2;
	if tnum>=k then 
		begin
			ll:=tree[code].left+t2;
			rr:=tree[code].left+t1-1;
			find:=Find(code*2,ll,rr,k,dep+1);
		end else 
			begin
				ll:=tree[code].mid+1+l-tree[code].left-t2;
				rr:=ll-l+r-tnum;
				find:=Find(code*2+1,ll,rr,k-tnum,dep+1);
			end;
end;
	
	
BEGIN

	readln(n,m);
	randomize;
	for i:=1 to n do
		begin
			read(g[0,i]);
			b[i]:=g[0,i];
		end;
	Qsort(1,n);
	Build_Tree(1,1,n,1);
	while m>0 do 
		begin
			readln(x,y,z);
			writeln(Find(1,x,y,z,1));
			dec(m);
		end;

END.

转载于:https://www.cnblogs.com/Thispoet/archive/2011/09/29/2195689.html

资源下载链接为: https://pan.quark.cn/s/d9ef5828b597 在本文中,我们将探讨如何通过 Vue.js 实现一个带有动画效果的“回到顶部”功能。Vue.js 是一款用于构建用户界面的流行 JavaScript 框架,其组件化和响应式设计让实现这种交互功能变得十分便捷。 首先,我们来分析 HTML 代码。在这个示例中,存在一个 ID 为 back-to-top 的 div 元素,其中包含两个 span 标签,分别显示“回到”和“顶部”文字。该 div 元素绑定了 Vue.js 的 @click 事件处理器 backToTop,用于处理点击事件,同时还绑定了 v-show 指令来控制按钮的显示与隐藏。v-cloak 指令的作用是在 Vue 实例渲染完成之前隐藏该元素,避免出现闪烁现象。 CSS 部分(backTop.css)主要负责样式设计。它首先清除了一些默认的边距和填充,对 html 和 body 进行了全屏布局,并设置了相对定位。.back-to-top 类则定义了“回到顶部”按钮的样式,包括其位置、圆角、阴影、填充以及悬停时背景颜色的变化。此外,与 v-cloak 相关的 CSS 确保在 Vue 实例加载过程中隐藏该元素。每个 .page 类代表一个页面,每个页面的高度设置为 400px,用于模拟多页面的滚动效果。 接下来是 JavaScript 部分(backTop.js)。在这里,我们创建了一个 Vue 实例。实例的 el 属性指定 Vue 将挂载到的 DOM 元素(#back-to-top)。data 对象中包含三个属性:backTopShow 用于控制按钮的显示状态;backTopAllow 用于防止用户快速连续点击;backSeconds 定义了回到顶部所需的时间;showPx 则规定了滚动多少像素后显示“回到顶部”按钮。 在 V
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值