权值线段树
权值线段树是什么
我们一般的线段树的节点下标是数组,而我们只要把它变成值,就能统计每个节点的数量了。
类似于桶的实现吧。
其实这个的线段树就是前缀和,也可以用树状数组来代替。
至于查询k大,只要二分就可以了。
数据范围大的时候通常先离散化数据,所以算半个离线数据结构。
直接上代码
拿洛谷的平衡树模板为例。
这里由于懒得写线段树就拿树状数组代替了。
如果开心的话手动改成线段树就可以了。
1 #include2 using namespace std; 3 const int N=1e6+1000; 4 int read(){ 5 char c;int num,f=1; 6 while(c=getchar(),!isdigit(c))if(c=='-')f=-1;num=c-'0'; 7 while(c=getchar(), isdigit(c))num=num*10+c-'0'; 8 return f*num; 9 } 10 int order[N],act[N][2],cnt,t[N],n; 11 bool cmp(int a,int b){return a<b;} 12 int fd(int a){ 13 int l=1,r=cnt,mid; 14 while(l<=r){ 15 mid=(l+r)>>1; 16 if(order[mid]==a)return mid; 17 else if(order[mid]>a)r=mid-1; 18 else l=mid+1; 19 } 20 return -1; 21 } 22 void add(int x,int val){for(;x<=cnt;x+=x&-x)t[x]+=val;} 23 int query(int x){ 24 int ans=0; 25 for(;x;x-=x&-x)ans+=t[x]; 26 return ans; 27 } 28 void Insert(int x){add(x,1);} 29 void Del(int x){if(query(x)-query(x-1))add(x,-1);} 30 int Getrank(int x){return query(x-1)+1;} 31 int Getnum(int rk){ 32 int l=0,r=cnt,mid,a,b; 33 while(l<=r){ 34 mid=(l+r)>>1; 35 a=query(mid-1); 36 b=query(mid); 37 if(b>=rk&&a return order[mid]; 38 if(b 1; 39 else r=mid-1; 40 } 41 return -1; 42 } 43 int Getpre(int x){return Getnum(Getrank(x)-1);} 44 int Getnxt(int x){return Getnum(query(x)+1);} 45 46 int main() 47 { 48 n=read(); 49 for(int i=1;i<=n;i++){ 50 act[i][0]=read(); 51 act[i][1]=read(); 52 order[++cnt]=act[i][1]; 53 } 54 sort(order+1,order+1+cnt,cmp); 55 cnt=unique(order+1,order+1+cnt)-order; 56 for(int i=1;i<=n;i++){ 57 int opt=act[i][0],x=fd(act[i][1]); 58 if(opt==1)Insert(x); 59 if(opt==2)Del(x); 60 if(opt==3)printf("%d\n",Getrank(x)); 61 if(opt==4)printf("%d\n",Getnum(act[i][1])); 62 if(opt==5)printf("%d\n",Getpre(x)); 63 if(opt==6)printf("%d\n",Getnxt(x)); 64 } 65 return 0; 66 }