【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)

 1 var t:array[0..2000000]of record
 2                            l,r,s:longint;
 3                           end;
 4     a,b,c,d,root:array[0..210000]of longint;
 5     n,m,i,x,y,k,cnt:longint;
 6 
 7 procedure swap(var x,y:longint);
 8 var t:longint;
 9 begin
10  t:=x; x:=y; y:=t;
11 end;
12 
13 procedure qsort(l,r:longint);
14 var i,j,mid:longint;
15 begin
16  i:=l; j:=r; mid:=a[(l+r)>>1];
17  repeat
18   while mid>a[i] do inc(i);
19   while mid<a[j] do dec(j);
20   if i<=j then
21   begin
22    swap(a[i],a[j]);
23    swap(c[i],c[j]);
24    inc(i); dec(j);
25   end;
26  until i>j;
27  if l<j then qsort(l,j);
28  if i<r then qsort(i,r);
29 end;
30 
31 procedure update(l,r:longint;var p:longint;x:longint);
32 var mid:longint;
33 begin
34  inc(cnt);
35  t[cnt]:=t[p];
36  p:=cnt;
37  inc(t[p].s);
38  if l=r then exit;
39  mid:=(l+r)>>1;
40  if x<=mid then update(l,mid,t[p].l,x)
41   else update(mid+1,r,t[p].r,x);
42 end;
43 
44 function query(p1,p2,l,r,k:longint):longint;
45 var mid,tmp:longint;
46 begin
47  if l=r then exit(l);
48  tmp:=t[t[p2].l].s-t[t[p1].l].s;
49  mid:=(l+r)>>1;
50  if tmp>=k then exit(query(t[p1].l,t[p2].l,l,mid,k))
51   else exit(query(t[p1].r,t[p2].r,mid+1,r,k-tmp));
52 end;
53 
54 begin
55  assign(input,'poj2104.in'); reset(input);
56  assign(output,'poj2104.out'); rewrite(output);
57  readln(n,m);
58  for i:=1 to n do
59  begin
60   read(a[i]); b[i]:=a[i]; c[i]:=i;
61  end;
62  qsort(1,n);
63  d[c[1]]:=1;
64  for i:=2 to n do
65   if a[i]<>a[i-1] then d[c[i]]:=d[c[i-1]]+1
66    else d[c[i]]:=d[c[i-1]];
67  for i:=1 to n do
68  begin
69   root[i]:=root[i-1];
70   update(1,n,root[i],d[i]);
71  end;
72  for i:=1 to m do
73  begin
74   readln(x,y,k);
75   writeln(a[query(root[x-1],root[y],1,n,k)]);
76  end;
77  close(input);
78  close(output);
79 end.

 UPD(2018.9.19):C++

  1 //无修改区间第K小值
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<string>
  5 #include<cmath>
  6 #include<iostream>
  7 #include<algorithm>
  8 #include<map>
  9 #include<set>
 10 #include<queue>
 11 #include<vector>
 12 using namespace std;
 13 typedef long long ll;
 14 typedef unsigned int uint;
 15 typedef unsigned long long ull;
 16 typedef pair<int,int> PII;
 17 typedef vector<int> VI;
 18 #define fi first
 19 #define se second 
 20 #define MP make_pair
 21 #define N   210000
 22 #define MOD 1000000007
 23 #define eps 1e-8 
 24 #define pi acos(-1)
 25 #define oo 1e9
 26 
 27 struct arr
 28 {
 29     int l,r,s;
 30 }t[2100000];
 31 int a[N],b[N],c[N],root[N],cnt,n;
 32 
 33 
 34 int read()
 35 { 
 36    int v=0,f=1;
 37    char c=getchar();
 38    while(c<48||57<c) {if(c=='-') f=-1; c=getchar();}
 39    while(48<=c&&c<=57) v=(v<<3)+v+v+c-48,c=getchar();
 40    return v*f;
 41 }
 42 
 43 int Discrete(int x)
 44 {
 45     int l=1;
 46     int r=n;
 47     while(l<=r)
 48     {
 49         int mid=(l+r)>>1;
 50         if(b[mid]==x) return c[mid];
 51         if(b[mid]<x) l=mid+1;
 52          else r=mid-1;
 53     }
 54 }
 55 
 56 void update(int l,int r,int x,int &p)
 57 {
 58     t[++cnt].l=t[p].l;
 59     t[cnt].r=t[p].r;
 60     t[cnt].s=t[p].s;
 61     p=cnt;
 62     t[p].s++;
 63     if(l==r) return;
 64     int mid=(l+r)>>1;
 65     if(x<=mid) update(l,mid,x,t[p].l);
 66      else update(mid+1,r,x,t[p].r);
 67 } 
 68     
 69 int query(int p1,int p2,int l,int r,int k)
 70 {
 71     if(l==r) return l;
 72     int tmp=t[t[p2].l].s-t[t[p1].l].s;
 73     int mid=(l+r)>>1;
 74     if(tmp>=k) return query(t[p1].l,t[p2].l,l,mid,k); 
 75      else return query(t[p1].r,t[p2].r,mid+1,r,k-tmp);
 76 }
 77 
 78 int main()
 79 {
 80     //freopen("poj2104.in","r",stdin);
 81     //freopen("poj2104.out","w",stdout);
 82     int m;
 83     scanf("%d%d",&n,&m);
 84     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
 85     for(int i=1;i<=n;i++) b[i]=a[i];
 86     sort(b+1,b+n+1);
 87     c[1]=1;
 88     for(int i=2;i<=n;i++)
 89     {
 90         c[i]=c[i-1];
 91         if(b[i]!=b[i-1]) c[i]++;
 92     }        
 93     for(int i=1;i<=n;i++) a[i]=Discrete(a[i]); //离散化
 94     for(int i=1;i<=n;i++)
 95     {
 96         root[i]=root[i-1];
 97         update(1,n,a[i],root[i]);
 98     }
 99     for(int i=1;i<=m;i++)
100     {
101         int x,y,k;
102         scanf("%d%d%d",&x,&y,&k);
103         int ans=b[query(root[x-1],root[y],1,n,k)];
104         printf("%d\n",ans);
105     }
106     
107     return 0;
108 }
109 
110             
111         

 

posted on 2016-12-04 16:06  myx12345  阅读(184)  评论(0编辑  收藏  举报

导航