题意:有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 ",ans); 105 } 106 107 return 0; 108 } 109 110 111