3196: Tyvj 1730 二逼平衡树

7 篇文章 0 订阅
2 篇文章 0 订阅

3196: Tyvj 1730 二逼平衡树

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

Sample Output

2
4
3
4
9

HINT

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


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


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

Source

[ Submit][ Status][ Discuss]

首先,,这个必须树套树
苟蒻首先想到的是树状数组套线段树,不过苟蒻的写法略吃内存,MLE
然后,,线段树套treap可以解决内存问题
但是套treap造成常数巨大,,,TLE
现在就是写法的问题,,,
首先,插入和删除操作用指针,快一些
然后treap的每个点可以不仅仅只存一个元素,可以存多个
w[x]代表这个元素在这个点重复多少次
这样可以省去Max和Min数组的维护
#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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值