@zzzc18
2017-06-23T09:35:40.000000Z
字数 4915
阅读 1586
线段树 Treap
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
1.查询k在区间内的排名
2.查询区间内排名为k的值
3.修改某一位值上的数值
4.查询k在区间内的前驱(前驱定义为严格小于x,且最大的数,若不存在输出-2147483647)
5.查询k在区间内的后继(后继定义为严格大于x,且最小的数,若不存在输出2147483647)
总之上面的询问就是树套树的套路了
洛谷上的数据很铁,时间也紧,不加奇技淫巧的优化本方法过不了(正解往往是CDQ分治和zky线段树等)
我就(zhi)说(hui)Treap+线段树
询问是区间内的,所以线段树在外层,Treap在内层
每一个线段树节点是一个Treap //参见Build函数
由于每个节点单独一个Treap开不下,Treap的空间要统一使用,但每个Treap有自己的root和size //见node
操作1:和线段树的查询一样,只不过在区间内要用Treap去找比查询值小的数的个数,求和后再加1
操作2:看代码,通过二分找到其值究竟是多少
操作3:线段树单点修改,在经过节点的Treap删去原来的值,加入新值
操作4,5:凡是满足条件的线段树区间内都用Treap把前驱后继求一下,前驱取最大值,后继取最小值(注意返回值:若没有找到,前驱返回-INF,后即返回INF)
讲完了。。。
#prag\ma GCC optimize("O3")#include<cstdio>#include<cstdlib>#include<algorithm>#define MAXN 1200009#define INF 0x7fffffffusing namespace std;int n,m;int a[MAXN];struct T_T{int ls,rs,rd,sz,num,val;}node[MAXN];int size;class Tree_Heap{public:int root,ans;int m;void update(int x){node[x].sz=node[node[x].ls].sz+node[node[x].rs].sz+node[x].num;}void rotate_l(int &k){int y=node[k].rs;node[k].rs=node[y].ls;node[y].ls=k;node[y].sz=node[k].sz;update(k);k=y;}void rotate_r(int &k){int y=node[k].ls;node[k].ls=node[y].rs;node[y].rs=k;node[y].sz=node[k].sz;update(k);k=y;}void insert(int &k,int v){if(k==0){size++;k=size;node[k].val=v;node[k].sz=node[k].num=1;node[k].rd=rand();return;}node[k].sz++;if(node[k].val==v){node[k].num++;}else if(v>node[k].val){insert(node[k].rs,v);if(node[node[k].rs].rd<node[k].rd)rotate_l(k);}else{insert(node[k].ls,v);if(node[node[k].ls].rd<node[k].rd)rotate_r(k);}}void del(int &k,int v){if(k==0)return;if(node[k].val==v){if(node[k].num>1){node[k].sz--;node[k].num--;return;}if(node[k].ls==0 || node[k].rs==0)k=node[k].ls+node[k].rs;else if(node[node[k].ls].rd<node[node[k].rs].rd){rotate_r(k);del(k,v);}else{rotate_l(k);del(k,v);}}else if(node[k].val<v){node[k].sz--;del(node[k].rs,v);}else{node[k].sz--;del(node[k].ls,v);}}int n2r(int x){int u=root;int re=1;while(u){if(node[u].val<x){re+=node[node[u].ls].sz+node[u].num;u=node[u].rs;}elseu=node[u].ls;}return re;}int r2n(const int &k,int x){if(k==0) return 0;if(x<=node[node[k].ls].sz) return r2n(node[k].ls,x);else if(x>node[node[k].ls].sz+node[k].num)return r2n(node[k].rs,x-node[k].num-node[node[k].ls].sz);else return node[k].val;}void pred(const int &k,int x){if(k==0)return;if(node[k].val<x){ans=k;pred(node[k].rs,x);}else{pred(node[k].ls,x);}}void succ(const int &k,int x){if(k==0)return;if(node[k].val>x){ans=k;succ(node[k].ls,x);}elsesucc(node[k].rs,x);}int Succ(int x){ans=0;succ(root,x);return ans?node[ans].val:INF;}int Pred(int x){ans=0;pred(root,x);return ans?node[ans].val:-INF;}void INS(int x){insert(root,x);}void DEL(int x){del(root,x);}int N2R(int x){return n2r(x);}void DEBUG(int k){if(k==0)return;DEBUG(node[k].ls);printf("DEBUG-------%d\n",node[k].val);DEBUG(node[k].rs);}};class Segment_Tree_For_Treap{public:Tree_Heap Treap[MAXN];int cnt;struct T_T_T{int ls,rs,left_range,right_range;}tree[MAXN];int rank(int k,int l,int r,int v){if(l<=tree[k].left_range && tree[k].right_range<=r){int t=Treap[k].N2R(v)-1;return t;}int re=0;int mid=(tree[k].left_range+tree[k].right_range)>>1;if(l<=mid) re+=rank(tree[k].ls,l,r,v);if(mid+1<=r) re+=rank(tree[k].rs,l,r,v);return re;}int Build(int l,int r){int now=++cnt;tree[now].left_range=l;tree[now].right_range=r;if(l==r){Treap[now].INS(a[l]);//Treap[now].DEBUG(Treap[now].root);//printf("\n\n");return now;}for(int i=l;i<=r;i++){Treap[now].INS(a[i]);//Treap[now].DEBUG(Treap[now].root);//printf("\n\n");}int mid=(l+r)>>1;tree[now].ls=Build(l,mid);tree[now].rs=Build(mid+1,r);return now;}void change(int k,int pos,int v){Treap[k].DEL(a[pos]);Treap[k].INS(v);//Treap[k].DEBUG(Treap[k].root);//printf("\n\n");if(tree[k].left_range==tree[k].right_range){a[pos]=v;return;}int mid=(tree[k].left_range+tree[k].right_range)>>1;if(pos<=mid)change(tree[k].ls,pos,v);else change(tree[k].rs,pos,v);}int Pred(int k,int l,int r,int v){if(l<=tree[k].left_range && tree[k].right_range<=r){return Treap[k].Pred(v);}int s=-INF;int mid=(tree[k].left_range+tree[k].right_range)>>1;if(l<=mid) s=max(s,Pred(tree[k].ls,l,r,v));if(mid+1<=r) s=max(s,Pred(tree[k].rs,l,r,v));return s;}int Succ(int k,int l,int r,int v){if(l<=tree[k].left_range && tree[k].right_range<=r){return Treap[k].Succ(v);}int s=INF;int mid=(tree[k].left_range+tree[k].right_range)>>1;if(l<=mid) s=min(s,Succ(tree[k].ls,l,r,v));if(mid+1<=r) s=min(s,Succ(tree[k].rs,l,r,v));return s;}int n2r(int l,int r,int val){return rank(1,l,r,val)+1;}int r2n(int k,int l,int r,int v){int ll=0,rr=100000000;while(ll<=rr){int mid=(ll+rr)>>1;if(n2r(l,r,mid)>v) rr=mid-1;else ll=mid+1;}return rr;}}Seg;int zz(){scanf("%d%d",&n,&m);int i;for(i=1;i<=n;i++)scanf("%d",&a[i]);Seg.Build(1,n);for(i=1;i<=m;i++){int opt,l,r,k,pos;scanf("%d",&opt);if(opt==1){scanf("%d%d%d",&l,&r,&k);printf("%d\n",Seg.n2r(l,r,k));}if(opt==2){scanf("%d%d%d",&l,&r,&k);printf("%d\n",Seg.r2n(1,l,r,k));}if(opt==3){scanf("%d%d",&pos,&k);Seg.change(1,pos,k);}if(opt==4){scanf("%d%d%d",&l,&r,&k);printf("%d\n",Seg.Pred(1,l,r,k));}if(opt==5){scanf("%d%d%d",&l,&r,&k);printf("%d\n",Seg.Succ(1,l,r,k));}}return 0;}int zzz=zz();int main(){;}