@zzzc18
2017-06-23T17:35:40.000000Z
字数 4915
阅读 1296
线段树
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 0x7fffffff
using 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;
}
else
u=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);
}
else
succ(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(){
;
}