【bzoj3196】 Tyvj1730—二逼平衡树

http://www.lydsy.com/JudgeOnline/problem.php?id=3196 (题目链接)

题意

  1.查询k在区间内的排名;2.查询区间内排名为k的值;3.修改某一位值上的数值;4.查询k在区间内的前驱(前驱定义为小于x,且最大的数);5.查询k在区间内的后继(后继定义为大于x,且最小的数)

Solution

  修改不好搞,主席树套树状数组空间炸,最好的选择→_→:线段树套treap。

  对于操作2,我们二分找到一个排名大于$k$的最小的数,然后查询这个数的前驱即可。

细节

  查询前驱和后继的时候要特判一下没有找到的情况。

代码

// bzoj3196
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define inf 2147483640
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
using namespace std;

const int maxn=50010;
int a[maxn],n,m;
struct node {
	int son[2],l,r,w,val,rnd,size,tree;
	int& operator [] (int x) {return son[x];}
};

namespace Treap {
	int sz;node tr[maxn*50];
	void pushup(int x) {
		tr[x].size=tr[tr[x][0]].size+tr[tr[x][1]].size+tr[x].w;
	}
	void rotate(int &x,int p) {
		int y=tr[x][p];
		tr[x][p]=tr[y][p^1];tr[y][p^1]=x;x=y;
		pushup(tr[y][p^1]);pushup(y);
	}
	void insert(int &k,int x) {
		if (!k) {tr[k=++sz].val=x;tr[k].rnd=rand();tr[k].size=tr[k].w=1;return;}
		int p=x>tr[k].val;tr[k].size++;
		if (x==tr[k].val) {tr[k].w++;return;}
		insert(tr[k][p],x);
		if (tr[tr[k][p]].rnd>tr[k].rnd) rotate(k,p);
	}
	void erase(int &k,int x) {
		if (!k) return;
		if (tr[k].val==x) {
			if (tr[k].w>1) {tr[k].w--;tr[k].size--;return;}
			if (tr[k][0]*tr[k][1]==0) k=tr[k][0]+tr[k][1];
			else rotate(k,tr[tr[k][1]].rnd>tr[tr[k][0]].rnd),erase(k,x);
		}
		else tr[k].size--,erase(tr[k][x>tr[k].val],x);
	}
	int rank(int k,int x) {
		if (!k) return 0;
		if (x<=tr[k].val) return rank(tr[k][0],x);
		else return rank(tr[k][1],x)+tr[tr[k][0]].size+tr[k].w;
	}
	int find(int k,int x) {
		if (!k) return -1;
		if (tr[tr[k][0]].size<x && x<=tr[tr[k][0]].size+tr[k].w) return tr[k].val;
		else if (x<=tr[tr[k][0]].size) return find(tr[k][0],x);
		else return find(tr[k][1],x-tr[tr[k][0]].size-tr[k].w);
	}
	int pref(int k,int x) {return find(k,rank(k,x));}
	int suff(int k,int x) {return find(k,rank(k,x+1)+1);}
}

namespace Segtree {
	node tr[maxn<<2];
	void build(int k,int s,int t) {
		tr[k].l=s;tr[k].r=t;
		for (int i=s;i<=t;i++) Treap::insert(tr[k].tree,a[i]);
		if (s==t) return;
		int mid=(s+t)>>1;
		build(k<<1,s,mid);build(k<<1|1,mid+1,t);
	}
	void modify(int k,int p,int val) {
		int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1;
		Treap::erase(tr[k].tree,a[p]);
		Treap::insert(tr[k].tree,val);
		if (l==r) return;
		if (p<=mid) modify(k<<1,p,val);
		else modify(k<<1|1,p,val);
	}
	int rank(int k,int s,int t,int val) {
		int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1;
		if (s==l && t==r) return Treap::rank(tr[k].tree,val);
		if (t<=mid) return rank(k<<1,s,t,val);
		else if (s>mid) return rank(k<<1|1,s,t,val);
		else return rank(k<<1,s,mid,val)+rank(k<<1|1,mid+1,t,val);
	}
	int pref(int k,int s,int t,int val) {
		int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1;
		if (s==l && t==r) {
			int tmp=Treap::pref(tr[k].tree,val);
			return tmp==-1 ? -inf : tmp;
		}
		if (t<=mid) return pref(k<<1,s,t,val);
		else if (s>mid) return pref(k<<1|1,s,t,val);
		else return max(pref(k<<1,s,mid,val),pref(k<<1|1,mid+1,t,val));
	}
	int suff(int k,int s,int t,int val) {
		int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1;
		if (s==l && t==r) {
			int tmp=Treap::suff(tr[k].tree,val);
			return tmp==-1 ? inf : tmp;
		}
		if (t<=mid) return suff(k<<1,s,t,val);
		else if (s>mid) return suff(k<<1|1,s,t,val);
		else return min(suff(k<<1,s,mid,val),suff(k<<1|1,mid+1,t,val));
	}
	int find(int s,int t,int k) {
		int l=0,r=1e8,res;
		while (l<=r) {
			int mid=(l+r)>>1;
			if (rank(1,s,t,mid)>=k) r=mid-1,res=mid;
			else l=mid+1;
		}
		return pref(1,s,t,res);
	}
}
using namespace Segtree;

int main() {
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++) scanf("%d",&a[i]);
	build(1,1,n);
	for (int op,x,y,k,i=1;i<=m;i++) {
		scanf("%d%d%d",&op,&x,&y);
		if (op==1) scanf("%d",&k),printf("%d\n",rank(1,x,y,k)+1);
		if (op==2) scanf("%d",&k),printf("%d\n",find(x,y,k));
		if (op==4) scanf("%d",&k),printf("%d\n",pref(1,x,y,k));
		if (op==5) scanf("%d",&k),printf("%d\n",suff(1,x,y,k));
		if (op==3) modify(1,x,y),a[x]=y;
	}
	return 0;
}

 

posted @ 2017-03-02 16:44  MashiroSky  阅读(330)  评论(0编辑  收藏  举报