bzoj 3196 Tyvj 1730 二逼平衡树(线段树套名次树)

 

3196: Tyvj 1730 二逼平衡树

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1807  Solved: 772
[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

9 6
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

2
4
3
4
9

HINT

 

1.n和m的数据范围:n,m<=50000


2.序列中每个数的数据范围:[0,1e8]


3.虽然原题没有,但事实上5操作的k可能为负数

 

【思路】

 

       线段树套名次树

       名次树上的各个操作和普通平衡树大致一样。

       一棵线段树,每一个节点为一棵Treap,各操作如下:

       操作1 -- 找出[l,r]内k的rank,得到比k小的数量s,则答案为s+1,在区间内统计比k小的数量即可。

       操作2 – 找出[l,r]内rank为k的数,二分查找该数M,通过操作1可以得到数M的rank,根据k与rank调整区间。

       操作3 – 修改pos上的数为k,在线段树上递归到位置pos,修改路径上的每一棵Treap,对应一次remove与一次insert。

       操作4 – 找出[l,r]内k的前驱,在区间每一棵包含区间的Treap上进行Treap中查找前驱的操作,更新ans。

       操作5 – 同理4

 

【代码】

  1 #include<cstdio>
  2 #include<ctime>
  3 #include<cstring>
  4 #include<cstdlib>
  5 #include<iostream>
  6 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
  7 using namespace std;
  8 
  9 const int N = 5*1e5+10;
 10 const int INF = 1e8;
 11 
 12 int n,m,val[N],tmp;
 13 //RANK TREE
 14 struct Node {
 15     Node* ch[2];
 16     int v,r,s,w;
 17     Node(int x):v(x) {ch[0]=ch[1]=NULL; s=w=1; r=rand();}
 18     void maintain() {
 19         s=w;
 20         if(ch[0]!=NULL) s+=ch[0]->s;
 21         if(ch[1]!=NULL) s+=ch[1]->s;
 22     }
 23     int cmp(int x) {
 24         if(x==v) return -1; else return x<v? 0:1;
 25     }
 26 };
 27 void rotate(Node* &o,int d) {
 28     Node* k=o->ch[d^1]; o->ch[d^1]=k->ch[d],k->ch[d]=o;
 29     o->maintain(),k->maintain(); o=k;
 30 }
 31 void insert(Node* &o,int x) {
 32     if(o==NULL) o=new Node(x);
 33     else {
 34         int d=o->cmp(x);
 35         if(d==-1) { o->w++; o->maintain(); return; }
 36         insert(o->ch[d],x);
 37         if(o->ch[d]->r > o->r) rotate(o,d^1);
 38     }
 39     o->maintain();
 40 }
 41 void remove(Node* &o,int x) {
 42     if(o==NULL) return;
 43     int d=o->cmp(x);
 44     if(d==-1) {
 45         Node* u=o;
 46         if(o->w>1) { o->w--;o->maintain();return; }
 47         if(o->ch[0]!=NULL&&o->ch[1]!=NULL) {
 48             int d2=o->ch[0]->r>o->ch[1]->r? 1:0;
 49             rotate(o,d2),remove(o->ch[d2],x);
 50         }
 51         else {
 52             if(o->ch[0]!=NULL) o=o->ch[0]; else o=o->ch[1];
 53             delete u;
 54         }
 55     } else remove(o->ch[d],x);
 56     if(o!=NULL) o->maintain();
 57 }
 58 void rank(Node* o,int x) {
 59     if(o==NULL) return ;
 60     int d=o->cmp(x),s=o->ch[0]==NULL? 0:o->ch[0]->s;
 61     if(d==-1) { tmp+=s; return ; }
 62     else if(d==0) rank(o->ch[0],x);
 63     else { tmp+=s+o->w; rank(o->ch[1],x); }
 64 }
 65 void before(Node* o,int x) {
 66     if(o==NULL) return ;
 67     if(o->v<x) { tmp=max(tmp,o->v); before(o->ch[1],x); }
 68     else before(o->ch[0],x);
 69 }
 70 void after(Node* o,int x) {
 71     if(o==NULL) return ;
 72     if(o->v>x) { tmp=min(tmp,o->v); after(o->ch[0],x); }
 73     else after(o->ch[1],x);
 74 }
 75 //SEGMENT TREE 2D
 76 Node* root[N>>1];
 77 void build(int u,int L,int R,int r,int x) {
 78     insert(root[u],x);
 79     if(L==R) return ;
 80     int M=(L+R)>>1;
 81     if(r<=M) build(u<<1,L,M,r,x);
 82     else build(u<<1|1,M+1,R,r,x);
 83 }
 84 void getrank(int u,int L,int R,int l,int r,int x) {
 85     if(l==L && r==R) { rank(root[u],x); return ; }
 86     int M=(L+R)>>1;
 87     if(r<=M) getrank(u<<1,L,M,l,r,x);
 88     else if(M<l) getrank(u<<1|1,M+1,R,l,r,x);
 89     else {
 90         getrank(u<<1,L,M,l,M,x);
 91         getrank(u<<1|1,M+1,R,M+1,r,x);
 92     }
 93 }
 94 void getindex(int x,int y,int k) {
 95     int num,L=0,R=INF,M;
 96     while(L<=R) {
 97         int M=(L+R)>>1;
 98         tmp=1;
 99         getrank(1,1,n,x,y,M);
100         if(tmp<=k) L=M+1,num=M;
101         else R=M-1;
102     }
103     printf("%d\n",num);
104 }
105 void change(int u,int L,int R,int r,int x,int y) {
106     remove(root[u],x),insert(root[u],y);
107     if(L==R) return ;
108     int M=(L+R)>>1;
109     if(r<=M) change(u<<1,L,M,r,x,y);
110     else change(u<<1|1,M+1,R,r,x,y);
111 }
112 void getbefore(int u,int L,int R,int l,int r,int x) {
113     if(l==L && R==r) { before(root[u],x);return ;}
114     int M=(L+R)>>1;
115     if(r<=M) getbefore(u<<1,L,M,l,r,x);
116     else if(l>M) getbefore(u<<1|1,M+1,R,l,r,x);
117     else {
118         getbefore(u<<1,L,M,l,M,x);
119         getbefore(u<<1|1,M+1,R,M+1,r,x);
120     }
121 }
122 void getafter(int u,int L,int R,int l,int r,int x) {
123     if(l==L && R==r) { after(root[u],x); return ;}
124     int M=(L+R)>>1;
125     if(r<=M) getafter(u<<1,L,M,l,r,x);
126     else if(l>M) getafter(u<<1|1,M+1,R,l,r,x);
127     else {
128         getafter(u<<1,L,M,l,M,x);
129         getafter(u<<1|1,M+1,R,M+1,r,x);
130     }
131 }
132 void read(int& x) {
133     char c=getchar(); int f=1; x=0;
134     while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}
135     while(isdigit(c)) x=x*10+c-'0',c=getchar();
136     x*=f;
137 }
138 void trav(Node* o) {
139     if(o==NULL) return ;
140     FOR(i,1,o->w) cout<<o->v<<" ";
141     trav(o->ch[0]),trav(o->ch[1]);
142 }
143 int main() {
144     //freopen("in.in","r",stdin);
145     //freopen("out.out","w",stdout);
146     read(n),read(m);
147     FOR(i,1,n) read(val[i]),build(1,1,n,i,val[i]);
148     int op,a,b,c;
149     while(m--) {
150         read(op),read(a),read(b);
151         switch(op) {
152             case 1:
153                 read(c); tmp=1; getrank(1,1,n,a,b,c);
154                 printf("%d\n",tmp);
155                 break;
156             case 2:
157                 read(c); getindex(a,b,c);
158                 break;
159             case 3:
160                 change(1,1,n,a,val[a],b); val[a]=b;
161                 break;
162             case 4:
163                 read(c); tmp=0; getbefore(1,1,n,a,b,c);
164                 printf("%d\n",tmp);
165                 break;
166             case 5:
167                 read(c); tmp=INF; getafter(1,1,n,a,b,c);
168                 printf("%d\n",tmp);
169                 break;
170         }
171     }
172     return 0;
173 }

 

你可能感兴趣的:(bzoj 3196 Tyvj 1730 二逼平衡树(线段树套名次树))