POJ2104 区间第k小

题意就是区间第k大……

题解:

前段时间用主席树搞掉了……

如今看到划分树,是在想来写一遍,结果18号对着学长的代码调了一上午连样例都没过,好桑心……

今天在做NOI2010超级钢琴,忽然发现用划分树很直观,果断决定再战划分树

对着网上的c++代码抄了一遍,A了,可是这编程复杂度有点高,忽然又看见盾哥的代码

很简短,和我原先的代码差不多,他怎么能A了呢……(后来发现区间第k小,我却写的第k大……sb啊)

考虑到盾哥的程序用到了离散化,因此没有考虑存在两个数相等的情况,这样就使代码减少很多

我报着试一试的心态把我认为肯定对的代码随机生成了几组大数据和盾哥的程序对拍,然后就对上了

好的,以后就用盾哥的程序

代码:

c++翻译来的:

 1 var  s,t:array[0..20,0..200000] of longint;
 2      a,rk:array[0..200000] of longint;
 3      i,n,m,x,y,k,j:longint;
 4  procedure sort(l,r:longint);
 5  var i,j,m,temp:longint;
 6  begin
 7  i:=l;j:=r;m:=a[(i+j)>>1];
 8  repeat
 9   while a[i]<m do inc(i);
10   while a[j]>m do dec(j);
11   if i<=j then
12    begin
13    temp:=a[i];a[i]:=a[j];a[j]:=temp;
14    inc(i);dec(j);
15    end;
16  until i>j;
17  if i<r then sort(i,r);
18  if j>l then sort(l,j);
19  end;
20   procedure init;
21    begin
22      readln(n,m);
23      for i:=1 to n do read(a[i]);t[0]:=a;
24      sort(1,n);
25    end;
26  procedure build(h,l,r:longint);
27   var  mid,i,lp,rp,lm:longint;
28   begin
29   mid:=(l+r)>>1;lm:=mid-l+1;lp:=l;rp:=mid+1;
30   for i:=l to mid do
31    if a[i]<a[mid] then dec(lm);
32   for i:=l to r do
33    begin
34    if i=l then s[h,i]:=0 else s[h,i]:=s[h,i-1];
35    if t[h,i]=a[mid] then
36     begin
37     if lm<>0 then
38      begin
39      dec(lm);inc(s[h,i]);t[h+1,lp]:=t[h,i];inc(lp);
40      end
41     else begin t[h+1,rp]:=t[h,i];inc(rp);end;
42     end
43    else
44     if t[h,i]<a[mid] then begin inc(s[h,i]);t[h+1,lp]:=t[h,i];inc(lp);end
45    else begin t[h+1,rp]:=t[h,i];inc(rp);end;
46    end;
47   if l=r then exit;
48   build(h+1,l,mid);
49   build(h+1,mid+1,r);
50   end;
51  function find(h,l,r,x,y,k:longint):longint;
52   var mid,ll,rr:longint;
53   begin
54   if l=r then exit(t[h,l]);
55   mid:=(l+r)>>1;
56   if l=x then ll:=0 else ll:=s[h,x-1];rr:=s[h,y]-ll;
57   if rr>=k then exit(find(h+1,l,mid,l+ll,l+ll+rr-1,k))
58   else exit(find(h+1,mid+1,r,mid+1+x-l-ll,mid+1+y-l-ll-rr,k-rr));
59   end;
60  procedure main;
61   begin
62    build(0,1,n);
63    for i:=1 to m do
64     begin
65      readln(x,y,k);
66      writeln(find(0,1,n,x,y,k));
67     end;
68   end;
69 begin
70   init;
71   main;
72 end.       

盾哥的:

 1 program poj2104; const maxn=200000;
 2 var
 3   a,b:array[0..maxn] of longint;
 4   s,d:array[1..20,0..maxn] of longint;
 5   n,m,i,j,x,y,z,ls,rs,mid,p:longint;
 6
 7 procedure sort(l,r:longint); var i,j,x,y:longint;
 8 begin
 9   i:=l;j:=r;x:=a[(i+j)>> 1];
10   repeat
11     while b[a[i]]<b[x] do inc(i);
12     while b[a[j]]>b[x] do dec(j);
13     if i<=j then begin
14       y:=a[i];a[i]:=a[j];a[j]:=y;
15       inc(i);dec(j);
16     end;
17   until i>j;
18   if l<j then sort(l,j);
19   if i<r then sort(i,r);
20 end;
21
22 procedure buildtree(h,l,r:longint);var mid:longint;
23 begin
24   if l=r then exit;
25   mid:=(l+r+1)>> 1;p:=0;
26   for i:=l to r do
27     if d[h,i]<mid then begin
28       d[h+1,l+p]:=d[h,i];
29       inc(p);s[h,i]:=p;
30     end else begin
31       d[h+1,mid+i-l-p]:=d[h,i];
32       s[h,i]:=p;
33     end;
34   buildtree(h+1,l,mid-1);
35   buildtree(h+1,mid,r);
36 end;
37
38 function find(h,ll,rr,l,r,k:longint):longint;
39 begin
40   if l=r then exit(d[h,r]);
41   if l=ll then ls:=0 else ls:=s[h,l-1];
42   rs:=s[h,r];mid:=(ll+rr+1)>> 1;
43   if rs-ls<k
44     then find:=find(h+1,mid,rr,l-ll-ls+mid,r-ll-rs+mid,k-rs+ls)
45     else find:=find(h+1,ll,mid-1,ls+ll,rs+ll-1,k);
46 end;
47
48 begin
49   readln(n,m);
50   for i:=1 to n do begin read(b[i]);a[i]:=i; end;
51   sort(1,n);
52   for i:=1 to n do d[1,a[i]]:=i;
53   buildtree(1,1,n);
54   for i:=1 to m do begin
55     readln(x,y,z);
56     writeln(b[a[find(1,1,n,x,y,z)]]);
57   end;
58 end.   

我最先抄的:

 1 const maxn=100000+10;
 2 type arrtype=array[0..maxn] of longint;
 3 var s,z:array[0..20,0..maxn] of longint;
 4     a,b,rk:arrtype;
 5     i,j,n,m,x,y,k:longint;
 6 procedure sort(var a:arrtype;l,r:longint);
 7  var i,j,m,temp:longint;
 8  begin
 9  i:=l;j:=r;m:=a[(i+j)>>1];
10  repeat
11   while a[i]<m do inc(i);
12   while a[j]>m do dec(j);
13   if i<=j then
14    begin
15    temp:=a[i];a[i]:=a[j];a[j]:=temp;
16    temp:=rk[i];rk[i]:=rk[j];rk[j]:=temp;
17    inc(i);dec(j);
18    end;
19  until i>j;
20  if i<r then sort(a,i,r);
21  if j>l then sort(a,l,j);
22  end;
23 procedure init;
24  begin
25  readln(n,m);
26  for i:=1 to n do read(a[i]);readln;b:=a;
27  for i:=1 to n do rk[i]:=i;
28  sort(a,1,n);
29  end;
30 procedure build(h,l,r:longint);
31  var i,p,mid:longint;
32  begin
33  mid:=(l+r)>>1;p:=0;
34  for i:=l to r do
35   if z[h,i]<=mid then
36    begin
37     z[h+1,l+p]:=z[h,i];
38     inc(p);
39     s[h,i]:=p;
40    end
41   else
42    begin
43     z[h+1,mid+1+i-p-l]:=z[h,i];
44     s[h,i]:=p;
45    end;
46  if l=r then exit;
47  build(h+1,l,mid);
48  build(h+1,mid+1,r);
49  end;
50 function find(h,l,r,x,y,k:longint):longint;
51  var ll,rr,mid:longint;
52  begin
53  if l=r then exit(z[h,l]);
54  mid:=(l+r)>>1;
55  if l=x then ll:=0 else ll:=s[h,x-1];rr:=s[h,y];
56  if rr-ll>=k then exit(find(h+1,l,mid,l+ll,l+rr-1,k))
57  else exit(find(h+1,mid+1,r,mid+1+x-l-ll,mid+1+y-l-rr,k-(rr-ll)));
58  end;
59 procedure main;
60  begin
61  for i:=1 to n do z[1,rk[i]]:=i;
62  build(1,1,n);
63  for i:=1 to m do
64   begin
65   readln(x,y,k);
66   writeln(b[rk[find(1,1,n,x,y,k)]]);
67   end;
68  end;
69 begin
70  init;
71  main;
72 end.        

盾哥的代码风格确实比我好很多,值得学习

POJ2104 区间第k小

时间: 2024-09-30 10:34:26

POJ2104 区间第k小的相关文章

poj 2104主席树求区间第k小

POJ - 2104 题意:求区间第k小 思路:无修改主席树 AC代码: #include "iostream" #include "iomanip" #include "string.h" #include "stack" #include "queue" #include "string" #include "vector" #include "set&

HDU 2665.Kth number 区间第K小

Kth number Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 11394    Accepted Submission(s): 3465 Problem Description Give you a sequence and ask you the kth big number of a inteval. Input The f

少年,想学带修改主席树吗 | BZOJ1901 带修改区间第k小

少年,想学带修改主席树吗 | BZOJ1901 带修改区间第k小 有一道题(BZOJ 1901)是这样的:n个数,m个询问,询问有两种:修改某个数/询问区间第k小. 不带修改的区间第k小用主席树很好写,不会的同学可以看一下这个. 加上修改怎么做呢?我们可以用数学老师成天讲的类比思想: 可以发现,不修改的区间k小问题中,每加入一个原序列中的数,对应的主席树在上一个的基础上进行修改,而查询的时候用右端点主席树减去左端点左边的主席树.这样的操作就像是维护前缀和:每次加入一个元素的时候,sum[i] =

【XSY2720】区间第k小 整体二分 可持久化线段树

题目描述 给你你个序列,每次求区间第\(k\)小的数. 本题中,如果一个数在询问区间中出现了超过\(w\)次,那么就把这个数视为\(n\). 强制在线. \(n\leq 100000,a_i<n,w\leq n\) 题解 考虑整体二分. 先看看离线要怎么做. 现在我们要计算每个数对每个区间的贡献. 对于每个询问区间和每种数,让这个区间最右边\(w\)个数对这个询问的贡献为\(1\),第\(w+1\)个数对这个询问的贡献为\(-w\). 这样每个数的贡献就是二维平面上的一个矩形.可以用扫描线+线段

HDU 5919 - Sequence II (2016CCPC长春) 主席树 (区间第K小+区间不同值个数)

HDU 5919 题意: 动态处理一个序列的区间问题,对于一个给定序列,每次输入区间的左端点和右端点,输出这个区间中:每个数字第一次出现的位子留下, 输出这些位子中最中间的那个,就是(len+1)/2那个. 思路: 主席树操作,这里的思路是从n到1开始建树.其他就是主席树查询区间第K小,计算区间不同值个数. #include <algorithm> #include <iterator> #include <iostream> #include <cstring&

主席树|求区间第k小模板

主席树 学了主席树,用来求区间上的第k小 写一下自己整理后的模板 求区间第k小 #include<bits/stdc++.h> using namespace std; //求区间第k小 const int maxn = 500010; struct node{ int v,lc,rc; }T[maxn * 21]; int n,m; int root[maxn]; int e; void insert(int pre,int cur,int pos,int l,int r){ if(l ==

POJ 2761(求区间第k小值)

Feed the dogs Time Limit: 6000MS   Memory Limit: 65536KB   64bit IO Format: %I64d & %I64u Submit Status Description Wind loves pretty dogs very much, and she has n pet dogs. So Jiajia has to feed the dogs every day for Wind. Jiajia loves Wind, but no

Splay树(区间第k小)——POJ 2761 Feed the dogs

对应POJ题目:点击打开链接 Feed the dogs Time Limit: 6000MS   Memory Limit: 65536K Total Submissions: 16655   Accepted: 5203 Description Wind loves pretty dogs very much, and she has n pet dogs. So Jiajia has to feed the dogs every day for Wind. Jiajia loves Win

poj2104求区间第k小,静态主席树入门模板

看了很久的主席树,最后看https://blog.csdn.net/williamsun0122/article/details/77871278这篇终于看懂了 #include <stdio.h> #include<algorithm> using namespace std; typedef long long ll; const int maxn = 1e5+5; int T[maxn],L[maxn*20],R[maxn*20],sum[maxn*20]; //sz[]为原