3196: Tyvj 1730 二逼平衡树
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1363 Solved: 579
[Submit][Status][Discuss]
Description
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
1.查询k在区间内的排名
2.查询区间内排名为k的值
3.修改某一位值上的数值
4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)
5.查询k在区间内的后继(后继定义为大于x,且最小的数)
Input
第一行两个数 n,m 表示长度为n的有序序列和m个操作
第二行有n个数,表示有序序列
下面有m行,opt表示操作标号
若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间[l,r]的排名
若opt=2 则为操作2,之后有三个数l,r,k 表示查询区间[l,r]内排名为k的数
若opt=3 则为操作3,之后有两个数pos,k 表示将pos位置的数修改为k
若opt=4 则为操作4,之后有三个数l,r,k 表示查询区间[l,r]内k的前驱
若opt=5 则为操作5,之后有三个数l,r,k 表示查询区间[l,r]内k的后继
Output
对于操作1,2,4,5各输出一行,表示查询结果
Sample Input
4 2 2 1 9 4 0 1 1
2 1 4 3
3 4 10
2 1 4 3
1 2 5 9
4 3 9 5
5 2 8 5
Sample Output
4
3
4
9
HINT
1.n和m的数据范围:n,m<=50000
2.序列中每个数的数据范围:[0,1e8]
【树套树】
线段树套平衡树还是很好理解的~
无非是要求在区间上进行平衡树的操作时用到
因为一个区间(线段树结点)对应的是一棵平衡树
所以在线段树上找到该区间后进行平衡树操作就好!
【switch语句:】
1\记得写break!
2\变量定义在switch外,否则会出现错误:error:jump to case label
switch(q){ case 1:... break; case 2:... break; case 3:... break; default:... break; }
【分析】Orz Regina8023:
以位置为关键字建一棵线段树,在线段树的每个节点上再建一棵以权值为关键字的treap即可。
五个操作的实现方法:
1.查询k在区间内排名(Getrank)
首先在线段树中找到区间的位置(Getrank),然后在找到的每一小段区间中的treap上找比k大的数的个数(Askrank),输出个数+1即可
2.查询区间内排名为k的值(Getnum)
首先二分答案(Getnum),然后用操作1中的Getrank找到目前二分出来的数在区间的排名,如果排名<=k,则在右半部分继续找,否则在左半部分
查询区间内排名为k的值与在一棵Treap上查找排名为k的元素不同!注意有多个区间,即多棵树
通过二分转化为查询k在区间内排名,这个问题好解决:分别在每个区间内查询比k小的元素,个数+1即可
3.修改某一位置上的数值(Modify)
这个操作等价于删除一个数,再插入一个数。但是要在线段树中每一个包含此数的区间都执行这两个操作。
4.查询前驱(Getpre)
在线段树中找到区间的位置,在每一个区间中找小于k的最大数,最后取最大值即可
5.查询后继(Getnext)
在线段树中找到区间的位置,在每一个区间中找小于k的最小数,最后取最小值即可
注意:
1.对于重复的数值的处理方法是在treap上维护一个weight,表示与当前结点的权值相同的数有几个。
2.查询操作要给全出口,否则就会死循环。。
MY CODE:
#include<bits/stdc++.h> #include<ctime> #define F(i,s,t) for(int i=(s);i<=(t);i++) #define D(i,s,t) for(int i=(t);i>=(s);i--) using namespace std; const int N=3e6; const int INF=1<<30; typedef long long LL; inline int getint() { int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } struct treap{int key,pro,weight,l,r,siz;}t[N]; inline void pushup(int p) { int l=t[p].l,r=t[p].r; t[p].siz=t[l].siz+t[r].siz+t[p].weight; } /*—————Zig/Zag—————*/ inline void zig(int &p) { int x=t[p].r; t[p].r=t[x].l; t[x].l=p; t[x].siz=t[p].siz; pushup(p); p=x; } inline void zag(int &p) { int y=t[p].l; t[p].l=t[y].r; t[y].l=p; t[y].siz=t[p].siz; pushup(p); p=y; } /*———————insert/delete——————*/ int n,m,x[N],q; int tot=0,ans,num,rt[N]; inline void newnode(int &p,int data) { p=++tot; t[p].weight=1; t[p].siz=1; t[p].key=data; t[p].pro=rand();//%((int)1e8); t[p].l=t[p].r=0; } inline void insert(int &p,int data) { if(!p){ newnode(p,data);return;} t[p].siz++; if(t[p].key==data){t[p].weight++;return;} if(t[p].key>data){ int l=t[p].l; insert(l,data); if(t[l].pro<t[p].pro) zag(p); }else{ int r=t[p].r; insert(r,data); if(t[r].pro<t[p].pro) zig(p); } } inline void delet(int &p,int data) { int l=t[p].l,r=t[p].r; if(data==t[p].key){ if(t[p].weight>1){ t[p].weight--; t[p].siz--; return; } if(t[p].l*t[p].r==0) p=t[p].l+t[p].r; else if(t[l].pro<t[r].pro){ zag(p); delet(p,data); } else{ zig(p); delet(p,data); } return; } t[p].siz--; if(t[p].key>data) delet(t[p].l,data); else delet(t[p].r,data); } /*——————operation——————*/ inline void askrank(int p,int data) { if(!p) return; int l=t[p].l,r=t[p].r; if(data==t[p].key){ans+=t[l].siz;return;}//+=!! if(data<t[p].key) {askrank(l,data);return;} ans=ans+t[l].siz+t[p].weight; askrank(r,data); } inline void pre(int p,int data) { if(!p) return; int l=t[p].l,r=t[p].r; if(t[p].key>=data) pre(l,data); else{ ans=max(ans,t[p].key); pre(r,data); } } inline void next(int p,int data) { if(!p) return; int l=t[p].l,r=t[p].r; if(t[p].key<=data) next(r,data); else{ ans=min(ans,t[p].key); pre(l,data); } } /*——————Segment tree——————*/ #define lson k<<1,l,mid #define rson k<<1|1,mid+1,r inline void build(int k,int l,int r,int pos,int data) { insert(rt[k],data);//rt[k]没有?新建一个! if(l==r) return; int mid=l+((r-l)>>1);// if(pos<=mid) build(lson,pos,data); else build(rson,pos,data); } inline void modify(int k,int l,int r,int pos,int data,int c) { delet(rt[k],data);///! insert(rt[k],c); if(l==r) return; int mid=l+((r-l)>>1); if(pos<=mid) modify(lson,pos,data,c); else modify(rson,pos,data,c); } inline void getrank(int k,int l,int r,int lx,int rx,int x) { if(lx<=l && r<=rx){ askrank(rt[k],x); return; } if(l==r) return; int mid=l+((r-l)>>1); if(lx<=mid) getrank(lson,lx,rx,x); if(rx>mid) getrank(rson,lx,rx,x); } inline void getnum(int l,int r,int rank) {//二分排名为k的数(数值),check其是否排名为k int lx=0,rx=1e8+1; while(lx<=rx){//左闭右开!! int mid=lx+((rx-lx)>>1); getrank(1,1,n,l,r,m); if(ans<=rank){ l=mid+1; num=m; } else rx=mid-1; } } inline void getpre(int k,int l,int r,int lx,int rx,int x) { if(lx<=l && r<=rx) {pre(rt[k],x);return;} if(l==r) return; int mid=l+((r-l)>>1); if(lx<=mid) getpre(lson,lx,rx,x); if(rx>mid) getpre(rson,lx,rx,x); } inline void getnext(int k,int l,int r,int lx,int rx,int x) { if(lx<=l && r<=rx) {next(rt[k],x);return;} if(l==r) return; int mid=l+((r-l)>>1); if(lx<=mid) getnext(lson,lx,rx,x); if(rx>mid) getnext(rson,lx,rx,x); } inline void Print(int x){printf("%d\n",x);} int main() { #ifndef ONLINE_JUDGE freopen("bzoj3196.txt", "r", stdin); #endif srand((unsigned)time(NULL)); n=getint();m=getint(); F(i,1,n) x[i]=getint(); F(i,1,n) build(1,1,n,i,x[i]); while(m--){ q=getint(); int l,r,k,pos,p; switch(q){ case 1://查询数值k在区间内的排名 l=getint();r=getint();k=getint(); ans=1; getrank(1,1,n,l,r,k); Print(ans); break; case 2://查询区间内排名为k的值 l=getint();r=getint();k=getint(); getnum(l,r,k); Print(num); break; case 3://修改某一位置pos上的数值->k pos=getint();k=getint(); p=x[pos]; x[pos]=k; modify(1,1,n,pos,p,k);//!!!! break; case 4://查询数值k在区间内的前驱 l=getint();r=getint();k=getint(); ans=0; getpre(1,1,n,l,r,k); Print(ans); break; case 5://5.查询k在区间内的后继 l=getint();r=getint();k=getint(); ans=INF;//! getnext(1,1,n,l,r,k); Print(ans); break; } } return 0; }
跟自己说声:加油,加油!