bzoj1901(動態區間第k大,樹套樹)

表示主席樹+樹狀數組懶得打了,學了樹套樹水過。。。

 

線段樹套平衡樹

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int N=12005;
const int inf=0x3f3f3f3f;
int n,m,tmp;
int c[N];
inline int read()
{
	int ans,f=1;char ch;
	while ((ch=getchar())<'0'||ch>'9') if (ch=='-') f=-1;ans=ch-'0';
	while ((ch=getchar())>='0'&&ch<='9') ans=ans*10+ch-'0';
	return ans*f;
}
int tot,size[N*18],fa[N*18],ch[N*18][2],cnt[N*18],val[N*18];
struct sigment
{
	int l,r;
	
	int rt;
	void up(int x)
	{
		size[x]=size[ch[x][0]]+size[ch[x][1]]+cnt[x];
	}
	void rot(int x)
	{
		int y=fa[x],z=fa[y],l,r;
		if (ch[y][0]==x) l=0;else l=1;r=l^1;
		if (z)
		if (ch[z][0]==y) ch[z][0]=x;else ch[z][1]=x;
		fa[x]=z;fa[y]=x;fa[ch[x][r]]=y;
		ch[y][l]=ch[x][r];ch[x][r]=y;
		up(y);
	}
	void splay(int x,int k)
	{
		int y,z;
		while (fa[x]!=k)
		{
			y=fa[x],z=fa[y];
			if (z!=k)
			if (ch[z][0]==y^ch[y][0]==x) rot(x);else rot(y);
			rot(x);
		}
		if (k==0) rt=x;
		up(x);
	}
	
	void insert(int x)
	{
		if (rt==0) 
		{
			rt=++tot;size[rt]=cnt[rt]=1;val[rt]=x;return ;
		}
		int k=rt;
		while (true)
		{
			size[k]++;
			if (val[k]==x) {cnt[k]++;return;}
			int y=ch[k][x>val[k]];
			if (!y)
			{
				++tot;
				fa[tot]=k;val[tot]=x;cnt[tot]=size[tot]=1;ch[k][x>val[k]]=tot;
				k=tot;break;
			}
			k=y;
		}
		splay(k,0);
	}
	int find(int i,int x)
	{
		if (val[i]==x) return i;
		if (val[i]>x) return find(ch[i][0],x);
		else return find(ch[i][1],x);
	}
	int small_num(int i,int x)
	{
		if (i==0) return 0;
		if (val[i]==x) return size[ch[i][0]];
		if (val[i]>x) return small_num(ch[i][0],x);
		return size[ch[i][0]]+cnt[i]+small_num(ch[i][1],x);
	}
	void del(int x)
	{
		int k=find(rt,x);
		splay(k,0);
		if (cnt[k]>1){cnt[k]--;size[k]--;return ;}
		if (ch[k][0]==0&&ch[k][1]==0) {rt=0;return ;}
		if (ch[k][0]==0) {rt=ch[k][1];fa[rt]=0;return ;}
		if (ch[k][1]==0) {rt=ch[k][0];fa[rt]=0;return ;}
		int y=ch[k][0];
		while (ch[y][1]) y=ch[y][1];
		splay(y,k);
		rt=y;fa[rt]=0;fa[ch[k][1]]=y;ch[y][1]=ch[k][1];
		up(y);
	}
}a[N*4];
void build(int i,int l,int r)
{
	a[i].l=l;a[i].r=r;
	for (int j=l;j<=r;j++) a[i].insert(c[j]);
	if (l==r) return ;
	int mid=(l+r)>>1;
	build(i<<1,l,mid);
	build(i<<1|1,mid+1,r);
}

void updata(int i,int l,int k)
{
	a[i].del(c[l]);
	a[i].insert(k);
	if (a[i].l==a[i].r) return ;
	int mid=(a[i].l+a[i].r)>>1;
	if (mid>=l) updata(i<<1,l,k);
	else updata(i<<1|1,l,k);
}
void find_rank(int i,int l,int r,int x)
{
	if (a[i].l==l&&a[i].r==r)
	{
		tmp+=a[i].small_num(a[i].rt,x);
		return;
	}
	int mid=(a[i].l+a[i].r)>>1;
	if (mid>=r) find_rank(i<<1,l,r,x);
	else if (mid<l) find_rank(i<<1|1,l,r,x);
	else find_rank(i<<1,l,mid,x),find_rank(i<<1|1,mid+1,r,x);
}
void rank_k(int l,int r,int x)
{
	int ml=0,mr=1e9,mid,ans=0;
	while(ml<=mr)
	{
		mid=(ml+mr)>>1;
		tmp=0;find_rank(1,l,r,mid);
		if (tmp<=x-1){ans=mid;ml=mid+1;}
		else mr=mid-1;
	}
	printf("%d\n",ans);
}
int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++) scanf("%d",&c[i]);
	build(1,1,n);
	
	int l,r,x;
	char ch[5];
	
	while (m--)
	{
		scanf("%s",ch);
		switch(ch[0])
		{
			case 'Q':scanf("%d%d%d",&l,&r,&x);rank_k(l,r,x);break;
			case 'C':scanf("%d%d",&l,&x);updata(1,l,x);c[l]=x;break;			
		}
	}
	
	return 0;
 } 


總結

1.果然這個數據範圍不寫讀入優化是不行的。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章