3196: Tyvj 1730 二逼平衡树
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2771 Solved: 1121
[ 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
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
4
3
4
9
HINT
1.n和m的数据范围:n,m<=50000
2.序列中每个数的数据范围:[0,1e8]
3.虽然原题没有,但事实上5操作的k可能为负数
Source
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<bitset>
#include<algorithm>
#include<cstring>
#include<map>
#include<stack>
#include<set>
#include<cmath>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
const int maxn = 5E4 + 50;
const int INF = ~0U>>1;
const int T = 25;
typedef unsigned short US;
int n,m,cnt,ch[maxn*T][2],num[maxn],va[maxn*T],L[maxn],R[maxn]
,K[maxn],Num[maxn*2],key[maxn*T],Root[maxn*4];
US typ[maxn],siz[maxn*T],w[maxn*T];
int getint()
{
char ch = getchar();
int ret = 0,Multi = 1;
while (ch < '0' || '9' < ch) {
if (ch == '-') Multi = -1;
ch = getchar();
}
while ('0' <= ch && ch <= '9') ret = ret*10 + ch - '0',ch = getchar();
return ret*Multi;
}
int New(int Num)
{
int ret = ++cnt; key[ret] = rand();
va[ret] = Num; siz[ret] = w[ret] = 1;
ch[ret][0] = ch[ret][1] = 0;
return ret;
}
void maintain(int x)
{
siz[x] = w[x];
if (ch[x][0]) siz[x] += siz[ch[x][0]];
if (ch[x][1]) siz[x] += siz[ch[x][1]];
}
void rotate(int &x,int d)
{
int y = ch[x][d];
ch[x][d] = ch[y][d^1]; maintain(x);
ch[y][d^1] = x; x = y; maintain(x);
}
void insert(int &x,int Num)
{
if (!x) {x = New(Num); return;}
if (Num == va[x]) {++w[x]; ++siz[x]; return;}
if (va[x] < Num) {
insert(ch[x][1],Num); maintain(x);
if (key[ch[x][1]] > key[x]) rotate(x,1);
}
else {
insert(ch[x][0],Num); maintain(x);
if (key[ch[x][0]] > key[x]) rotate(x,0);
}
maintain(x);
}
void Insert(int o,int l,int r,int pos,int Num)
{
insert(Root[o],Num);
if (l == r) return;
int mid = (l + r) >> 1;
if (pos <= mid) Insert(o<<1,l,mid,pos,Num);
else Insert(o<<1|1,mid+1,r,pos,Num);
}
int sum(int x,int po)
{
if (!x) return 0;
if (va[x] == po) return w[x] + siz[ch[x][0]];
if (va[x] > po) return sum(ch[x][0],po);
else return siz[ch[x][0]] + sum(ch[x][1],po) + w[x];
}
int Sum(int o,int l,int r,int ql,int qr,int po)
{
if (ql <= l && r <= qr) return sum(Root[o],po);
int mid = (l + r) >> 1,ret = 0;
if (ql <= mid) ret += Sum(o<<1,l,mid,ql,qr,po);
if (qr > mid) ret += Sum(o<<1|1,mid+1,r,ql,qr,po);
return ret;
}
void remove(int &x,int Num)
{
if (va[x] == Num) {
if (w[x] > 1) {--w[x]; --siz[x]; return;}
if (!ch[x][0] && !ch[x][1]) {x = 0; return;}
if (!ch[x][0] || !ch[x][1]) {
if (ch[x][0]) x = ch[x][0]; else x = ch[x][1];
return;
}
if (key[ch[x][0]] > key[ch[x][1]]) {
rotate(x,0);
remove(ch[x][1],Num);
}
else {
rotate(x,1);
remove(ch[x][0],Num);
}
maintain(x); return;
}
if (va[x] < Num) {
remove(ch[x][1],Num); maintain(x);
if (key[ch[x][1]] > key[x]) rotate(x,1);
}
else {
remove(ch[x][0],Num); maintain(x);
if (key[ch[x][0]] > key[x]) rotate(x,0);
}
maintain(x);
}
void Remove(int o,int l,int r,int pos,int Num,int num2)
{
remove(Root[o],Num);
insert(Root[o],num2);
if (l == r) return;
int mid = (l + r) >> 1;
if (pos <= mid) Remove(o<<1,l,mid,pos,Num,num2);
else Remove(o<<1|1,mid+1,r,pos,Num,num2);
}
int pre(int x,int k)
{
if (!x) return -INF;
int ret = -INF;
if (va[x] >= k) return pre(ch[x][0],k);
else return max(va[x],pre(ch[x][1],k));
}
int Pre(int o,int l,int r,int ql,int qr,int k)
{
if (ql <= l && r <= qr) return pre(Root[o],k);
int mid = (l + r) >> 1,ret = -INF;
if (ql <= mid) ret = max(ret,Pre(o<<1,l,mid,ql,qr,k));
if (qr > mid) ret = max(ret,Pre(o<<1|1,mid+1,r,ql,qr,k));
return ret;
}
int nex(int x,int k)
{
if (!x) return INF;
if (va[x] <= k) return nex(ch[x][1],k);
else return min(va[x],nex(ch[x][0],k));
}
int Nex(int o,int l,int r,int ql,int qr,int k)
{
if (ql <= l && r <= qr) return nex(Root[o],k);
int mid = (l + r) >> 1,ret = INF;
if (ql <= mid) ret = min(ret,Nex(o<<1,l,mid,ql,qr,k));
if (qr > mid) ret = min(ret,Nex(o<<1|1,mid+1,r,ql,qr,k));
return ret;
}
int nu;
char c[20];
void print( int k )
{
nu = 0;
while( k > 0 ) c[++nu] = k % 10, k /= 10;
while( nu )
putchar( c[nu--]+48 );
putchar( 10 );
}
int main()
{
//freopen("3196.in","r",stdin);
//freopen("3196.out","w",stdout);
n = getint(); m = getint();
int cur = 1,tot = 0;
for (int i = 1; i <= n; i++) {
num[i] = getint();
Insert(1,1,n,i,num[i]);
Num[++tot] = num[i];
}
for (int i = 1; i <= m; i++) {
typ[i] = getint();
L[i] = getint(); R[i] = getint();
if (typ[i] == 1) K[i] = getint();
else if (typ[i] == 2) K[i] = getint();
else if (typ[i] == 3) Num[++tot] = R[i];
else if (typ[i] == 4) K[i] = getint();
else K[i] = getint();
}
sort(Num + 1,Num + tot + 1);
for (int i = 2; i <= tot; i++)
if (Num[i] != Num[i-1])
Num[++cur] = Num[i];
for (int i = 1; i <= m; i++) {
if (typ[i] == 1) {
int l = L[i],r = R[i],k = K[i];
print(Sum(1,1,n,l,r,k-1) + 1);
}
else if (typ[i] == 2) {
int l = L[i],r = R[i],k = K[i];
int LL = 1,RR = cur;
while (RR - LL > 1) {
int mid = (LL + RR) >> 1;
if (Sum(1,1,n,l,r,Num[mid]) < k) LL = mid;
else RR = mid;
}
if (Sum(1,1,n,l,r,Num[LL]) >= k) print(Num[LL]);
else print(Num[RR]);
}
else if (typ[i] == 3) {
int pos = L[i],k = R[i];
Remove(1,1,n,pos,num[pos],k);
num[pos] = k;
}
else if (typ[i] == 4) {
int l = L[i],r = R[i],k = K[i];
print(Pre(1,1,n,l,r,k));
}
else {
int l = L[i],r = R[i],k = K[i];
print(Nex(1,1,n,l,r,k));
}
}
return 0;
}