BZOJ-3065 带插入区间K小值

这道题为树套树,我自己是替罪羊树套权值线段树。

此题有三种操作:

1.询问K值:可通过替罪羊树提取区间+权值线段树合并+二分答案求得

2.修改:可通过权值线段树的删除+添加操作实现

3.插入:可通过替罪羊树的插入操作实现

#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <cctype>
#define rep(i, l, r) for(int i=l; i<=r; i++)
#define clr(x, c) memset(x, c, sizeof(x))
#define inf 0x7fffffff
#define ll long long
#define maxn 80010
#define maxl 70010

#define l(x) Left[x]
#define r(x) Right[x]
#define s(x) Size[x]
#define k(x) Key[x]
#define t(x) Tree[x]
#define ls(x) Size[Left[x]]
#define rs(x) Size[Right[x]]
#define a 0.8

using namespace std;
inline int read()
{
	int x=0, f=1; char ch=getchar();
	while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
	while (isdigit(ch)) x=x*10+ch-'0', ch=getchar();
	return x*f;
}

//=========================================================================================

struct node
{
	node *l, *r; int sum;
	node () {sum=0; l=r=NULL;}
} *blank=new(node);
void Add(int l, int r, int k, node*&t)
{
	if (t==blank) t=new(node), t->l=t->r=blank;
	t->sum++;
	if (l==r) return; int mid=(l+r)>>1;
	if (k<=mid) Add(l, mid, k, t->l); else Add(mid+1, r, k, t->r);
}
void Del(int l, int r, int k, node*&t)
{
	t->sum--;
	if (l==r) return; int mid=(l+r)>>1;
	if (k<=mid) Del(l, mid, k, t->l); else Del(mid+1, r, k, t->r);
}

//=========================================================================================

int Left[maxn], Right[maxn], Key[maxn], Size[maxn], V=0, roof, dfn[maxn], top;
node *Tree[maxn];
void Build(int l, int r, int &t)
{
	if (l>r) {t=0; return;}
	int mid=(l+r)>>1; 
	t=dfn[mid], t(t)=blank, s(t)=r-l+1;
	rep(i, l, r) Add(0, maxl, k(dfn[i]), t(t));
	Build(l, mid-1, l(t)), Build(mid+1, r, r(t));
}
node *range[maxn];
int p[maxn], nr, np;
void ranging(int l, int r, int t) //BST查找区间
{
	if (r<ls(t)) ranging(l, r, l(t));  //全在左边
	else if (l>ls(t)) ranging(l-ls(t)-1, r-ls(t)-1, r(t)); //全在右边
	else if (!l && r==s(t)-1) range[++nr]=t(t); //整棵树都是
	else //分跨两边
	{
		p[++np]=k(t);
		if (l<ls(t)) ranging(l, ls(t)-1, l(t));
		if (r>ls(t)) ranging(0, r-ls(t)-1, r(t));
	}
}
void getrange(int l, int r){nr=np=0; ranging(l-1, r-1, roof);} 
void dfs(int t){if (l(t)) dfs(l(t)); dfn[++top]=t; if (r(t)) dfs(r(t));} //DFS序
void Recycle(node *t)  //回收节点
{
	if (!t->sum) return;
	if (t->l) Recycle(t->l);
	if (t->r) Recycle(t->r);
	delete(t);
}
void reBuild(int &t)
{
	top=0; dfs(t); 
	rep(i, 1, top) Recycle(t(dfn[i])); 
	Build(1, top, t);
}

//=========================================================================================

bool Insert(int r, int k, int h, int &t)
{
	if (!t)
	{
		t=++V;
		s(t)=1, k(t)=k, l(t)=r(t)=0, t(t)=blank;
		Add(0, maxl, k, t(t));
		return h>log(V)/log(1/a);
	}
	bool flag;
	if (r<=ls(t)) 
		flag=Insert(r, k, h+1, l(t));
	else flag=Insert(r-ls(t)-1, k, h+1, r(t));
	s(t)=ls(t)+rs(t)+1; Add(0, maxl, k, t(t));
	if (flag && (max(ls(t), rs(t)) > a*s(t))) {reBuild(t); return false;}
	return flag;
}
int Change(int r, int k, int t)
{
	if (ls(t)==r)
	{
		int v=k(t);
		Del(0, maxl, k(t), t(t));
		Add(0, maxl, k(t)=k, t(t));
		return v;
	}
	int v;
	if (r<ls(t)) v=Change(r, k, l(t));
	else v=Change(r-ls(t)-1, k, r(t));
	Del(0, maxl, v, t(t));
	Add(0, maxl, k, t(t));
	return v;
}
int Query(int l, int r, int rank)
{
	rank--;
	getrange(l, r);
	int L=0, R=maxl;
	while (L<R)
	{
		int mid=(L+R)>>1, sum=0;
		rep(i, 1, nr) sum+=range[i]->l->sum;
		rep(i, 1, np) sum+=(p[i]>=L && p[i]<=mid) ? 1 : 0;
		if (rank<sum)
			{rep(i, 1, nr) range[i]=range[i]->l; R=mid;}
		else
			{rank-=sum; rep(i, 1, nr) range[i]=range[i]->r; L=mid+1;}
	}
	return L;
}

//=========================================================================================

int n, m, w[maxn], last=0;
int main()
{
	blank->l=blank->r=blank;
	n=read(); rep(i, 1, n) w[i]=read();
	l(0)=r(0)=s(0)=0;
	rep(i, 1, n) dfn[i]=++V, k(V)=w[i];
	Build(1, n, roof);
	m=read();
	while (m--)
	{
		char ch=getchar(); while (ch!='Q' && ch!='M' && ch!='I') ch=getchar();
		if (ch=='Q')
		{
			int x=read()^last, y=read()^last, z=read()^last;
			printf("%d\n", last=Query(x, y, z));
		}
		else if (ch=='I')
		{
			int x=read()^last, y=read()^last;
			Insert(x-1, y, 0, roof);
		}
		else
		{
			int x=read()^last, y=read()^last;
			Change(x-1, y, roof);
		}
	}
	return 0;
}

  

posted @ 2015-04-21 20:20  NanoApe  阅读(198)  评论(0编辑  收藏  举报
AmazingCounters.com