The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with the query like to simply find the k-th smallest number of the given N numbers. They have developed a more powerful system such that for N numbers a[1], a[2], ..., a[N], you can ask it like: what is the k-th smallest number of a[i], a[i+1], ..., a[j]? (For some i<=j, 0<k<=j+1-i that you have given to it). More powerful, you can even change the value of some a[i], and continue to query, all the same.
Your task is to write a program for this computer, which
- Reads N numbers from the input (1 <= N <= 50,000)
- Processes M instructions of the input (1 <= M <= 10,000). These instructions include querying the k-th smallest number of a[i], a[i+1], ..., a[j] and change some a[i] to t.
Input
The first line of the input is a single number X (0 < X <= 4), the number of the test cases of the input. Then X blocks each represent a single test case.
The first line of each block contains two integers N and M, representing N numbers and M instruction. It is followed by N lines. The (i+1)-th line represents the number a[i]. Then M lines that is in the following format
Q i j k or
C i t
It represents to query the k-th number of a[i], a[i+1], ..., a[j] and change some a[i] to t, respectively. It is guaranteed that at any time of the operation. Any number a[i] is a non-negative integer that is less than 1,000,000,000.
There're NO breakline between two continuous test cases.
<b< dd="">
Output
For each querying operation, output one integer to represent the result. (i.e. the k-th smallest number of a[i], a[i+1],..., a[j])
There're NO breakline between two continuous test cases.
Sample Input
2
5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3
Sample Output
3
6
3
6
第一次写树套树,而且应该是最基础的树套树,手抄大佬函数,自己整理成结构体。
没看别人题解的时候再高数课上YY,以为是对于线段树的每个节点套一个平衡树,这样的话想了一下,开的空间大概是n*lgn*n,基本上是炸了的。
但是好像没有必要每个节点建立一个Treap,每个Treap给n个节点。因为过于浪费。
大佬们好像是只建立一个大Treap,但是有n个root,然后把空间分配到小Treap里面。
但是这样空间开n*lgn*lgn,好像1000000的空间还是不够处理极限情况啊。。。不知道这么回事。
copy from qscqesze 顾学姐?结合前两天写的线段树和Treap,我们两个的风格还是比较像的,所以我理解代码起来也比较快。ORZ。。。对于空间的问题,多做几个题再回头分析。
#include<iostream> #include<stdio.h> #include<algorithm> #include<cstring> #include<ctime> using namespace std; #define maxn 1000001 int tmp=0; struct Treap { int root[maxn],sz,s[maxn],ch[maxn][2],v[maxn],w[maxn],rnd[maxn];//s是size,w是cnt //rnd小根堆 void init() { memset(root,0,sizeof(root)); sz=0; } void Update(int now) { s[now]=s[ch[now][0]]+s[ch[now][1]]+w[now]; } void rotate(int &now,int p) { int t=ch[now][p]; ch[now][p]=ch[t][1-p],ch[t][1-p]=now,s[t]=s[now]; Update(now);now=t;//好像明白了为什么要替代:k得到儿子信息 } void Insert(int &now,int num) { if(!now){ now=++sz;s[now]=w[now]=1;ch[now][0]=ch[now][1]=0;rnd[now]=rand(); v[now]=num;return; } s[now]++; if(v[now]==num)w[now]++; else{ int t=num>v[now]; Insert(ch[now][t],num); if(rnd[ch[now][t]]<rnd[now]) rotate(now,t); } } void Del(int &now,int num)//code better than mine before { if(v[now]==num){ if(w[now]>1){ w[now]--; s[now]--; return; } if(ch[now][0]*ch[now][1]==0) now=ch[now][0]+ch[now][1]; else rotate(now,rnd[ch[now][0]]>rnd[ch[now][1]]),Del(now,num); } else { Del(ch[now][num>v[now]],num); s[now]--; } } void Find(int now,int num) { if(!now) return; if(v[now]<=num){ tmp+=s[ch[now][0]]+w[now]; Find(ch[now][1],num); } else Find(ch[now][0],num); } }Tr; /////////////////////线段树 void Seg_insert(int now,int l,int r,int x,int num) { Tr.Insert(Tr.root[now],num); if(l==r)return; int mid=(l+r)>>1; if(x<=mid)Seg_insert(now<<1,l,mid,x,num); else Seg_insert(now<<1|1,mid+1,r,x,num); } void Seg_change(int now,int l,int r,int x,int Now,int Pre) { Tr.Del(Tr.root[now],Pre); Tr.Insert(Tr.root[now],Now); if(l==r)return; int mid=(l+r)>>1; if(x<=mid)Seg_change(now<<1,l,mid,x,Now,Pre); else Seg_change(now<<1|1,mid+1,r,x,Now,Pre); } void Seg_query(int now,int l,int r,int L,int R,int num) { if(l==L&&r==R) { Tr.Find(Tr.root[now],num); return; } int mid = (l+r)>>1; if(mid>=R) Seg_query(now<<1,l,mid,L,R,num); else if(mid<L) Seg_query(now<<1|1,mid+1,r,L,R,num); else{ Seg_query(now<<1,l,mid,L,mid,num); Seg_query(now<<1|1,mid+1,r,mid+1,R,num); } } /////////////////////////// int a[maxn]; int main() { int T;scanf("%d",&T); while(T--) { Tr.init(); int n,m;scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); Seg_insert(1,1,n,i,a[i]); } char op[3]; for(int i=1;i<=m;i++){ scanf("%s",op); if(op[0]=='C'){ int x,y;scanf("%d%d",&x,&y); Seg_change(1,1,n,x,y,a[x]); a[x]=y; } else{ int x,y,z;scanf("%d%d%d",&x,&y,&z); int l = 0,r = 1e9; while(l<=r){ int mid = (l+r)>>1; tmp=0; Seg_query(1,1,n,x,y,mid); if(tmp>=z)r=mid-1; else l=mid+1; } printf("%d ",l); } } } return 0; }
(2700ms左右);
这题还有主席树(200ms左右)