bzoj 4923 K小值查询(Splay)

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


解法题解里说的挺清楚的,好吧,我就是找个地方存一哈代码...


辣鸡卡常题,跑了16s竟然判过了....实在是优化不动了




代码:

#include<bits/stdc++.h>
using namespace std;
const int MAXN=100010;
const int INF=2e9+5;
int a[MAXN];
int n,q;
namespace Splay_Tree
{
	#define Key_value ch[ch[root][1]][0] 
	int pre[MAXN],ch[MAXN][2],key[MAXN],size[MAXN],sub[MAXN],tmp[MAXN];
	int root,tot1,cnt;
	inline void NewNode(int &r,int father,int k)
	{
		r=++tot1;
		pre[r]=father;
		ch[r][0]=ch[r][1]=0;
		key[r]=k;
		size[r]=1;
		sub[r]=0;
	}
	inline void push_up(int r)
	{
		int lson=ch[r][0],rson=ch[r][1];
		size[r]=size[lson]+size[rson]+1;
	}
	inline void up_sub(int r,int k)
	{
		if(!r)
			return ;
		if(key[r]!=-1&&key[r]!=INF)
			key[r]-=k;
		sub[r]+=k;
	}
	inline void push_down(int r)
	{
		if(sub[r])
		{
			up_sub(ch[r][0],sub[r]);
			up_sub(ch[r][1],sub[r]);
			sub[r]=0;
		}
	}
	inline void Build(int &x,int l,int r,int father)
	{
		if(l>r)
			return;
		int mid=(l+r)/2;
		NewNode(x,father,a[mid]);
		Build(ch[x][0],l,mid-1,x);
		Build(ch[x][1],mid+1,r,x);
		push_up(x);
	}
	inline void Init()
	{
		root=tot1=0;
		ch[root][0]=ch[root][1]=size[root]=pre[root]=0;
		key[root]=0;
		sub[root]=0;
		NewNode(root,0,-1);
		NewNode(ch[root][1],root,INF);
		Build(Key_value,1,n,ch[root][1]);
		push_up(ch[root][1]);
		push_up(root);
	}
	//旋转,0为左旋,1为右旋 
	inline void Rotate(int x,int kind)
	{
		int y=pre[x];
		push_down(y);
		push_down(x);
		ch[y][!kind]=ch[x][kind];
		pre[ch[x][kind]]=y;
		if(pre[y])
			ch[pre[y]][ch[pre[y]][1]==y]=x;
		pre[x]=pre[y];
		ch[x][kind]=y;
		pre[y]=x;
		push_up(y);
	}
	//Splay调整,将r结点调整到goal下面 
	inline void Splay(int r,int goal)
	{
		push_down(r);
		while(pre[r]!=goal)
		{
			if(pre[pre[r]]==goal)
			{
				push_down(pre[r]);
				push_down(r);
				Rotate(r,ch[pre[r]][0]==r);
			}
			else
			{
				push_down(pre[pre[r]]);
				push_down(pre[r]);
				push_down(r);
				int y=pre[r];
				int kind=ch[pre[y]][0]==y;
				if(ch[y][kind]==r)
				{
					Rotate(r,!kind);
					Rotate(r,kind);
				}
				else
				{
					Rotate(y,kind);
					Rotate(r,kind);
				}
			}
		}
		push_up(r);
		if(goal==0)
			root=r;
	}
	//获得第K个位置数
	inline int Get_kth(int r,int k)
	{
		push_down(r);
		int t=size[ch[r][0]]+1;
		if(t==k)
			return r;
		if(t>k)
			return Get_kth(ch[r][0],k);
		else
			return Get_kth(ch[r][1],k-t);
	}
	inline int Get_mx(int r)
	{
		push_down(r);
		if(ch[r][1])
			return Get_mx(ch[r][1]);
		return r;
	}
	inline int Get_mi(int r)
	{
		push_down(r);
		if(ch[r][0])
			return Get_mx(ch[r][0]);
		return r;
	}
	inline int Get_ri(int r,int k)
	{
		int ret=-1;
		while(1)
		{
			push_down(r);
			if(key[r]>k)
			{
				ret=r;
				if(ch[r][0])
					r=ch[r][0];
				else
					return ret;
			}
			else
			{
				if(ch[r][1])
					r=ch[r][1];
				else
					return ret;
			}
		}
	}
	inline int Get_lf(int r,int k)
	{
		int ret=-1;
		while(1)
		{
			push_down(r);
			if(key[r]<=k)
			{
				ret=r;
				if(ch[r][1])
					r=ch[r][1];
				else
					return ret;
			}
			else
			{
				if(ch[r][0])
					r=ch[r][0];
				else
					return ret;
			}
		}
	}
	inline void InOrder(int r)
	{
		if(!r)
			return;
		push_down(r);
		InOrder(ch[r][0]);
		tmp[cnt++]=r;
		InOrder(ch[r][1]);
	}
	inline int Get_next(int r)
	{
	    push_down(r);
	    if(ch[r][1]==0)
			return -1;
	    r=ch[r][1];
		push_down(r);
	    while(ch[r][0])
	    {
	        r=ch[r][0];
	        push_down(r);
	    }
	    return r;
	}
	void Insert(int r,int now)
	{
		push_down(r);
		if(key[tmp[now]]<key[r])
		{
			if(ch[r][0])
			{
				Insert(ch[r][0],now);
			}
			else
			{
				pre[tmp[now]]=r;
				ch[r][0]=tmp[now];
				ch[tmp[now]][0]=ch[tmp[now]][1]=0;
				size[tmp[now]]=1;
				sub[tmp[now]]=0;
			}
			push_up(r);
		}
		if(key[tmp[now]]>=key[r])
		{
			if(ch[r][1])
			{
				Insert(ch[r][1],now);
			}
			else
			{
				pre[tmp[now]]=r;
				ch[r][1]=tmp[now];
				ch[tmp[now]][0]=ch[tmp[now]][1]=0;
				size[tmp[now]]=1;
				sub[tmp[now]]=0;
			}
			push_up(r);
		}
	}
	void change(int k)
	{
		int l=Get_lf(root,k);
		Splay(l,0);
		int r=Get_ri(root,k+k);
		Splay(r,root);
		if(key[ch[root][1]]!=INF)
		{
			key[ch[root][1]]-=k;
		}
		sub[ch[root][1]]+=k;
		push_down(ch[root][1]);
		if(Key_value==0)
			return ;
		int sv=Key_value;
		cnt=0;
		pre[sv]=0;
		Key_value=0;
		InOrder(sv);
		int now=0;
		while(now<cnt)
			Insert(root,now++);
	}
}
using namespace Splay_Tree;
inline char nc()
{
  static char buf[100000],*p1=buf,*p2=buf;
  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}

inline void rea(int &x)
{
  char c=nc(); x=0;
  for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}
int op,k;
int main()
{
	//freopen("in.in","r",stdin);
	//freopen("out.out","w",stdout);
	rea(n);rea(q);
	for(int i=1;i<=n;i++)
	{
		rea(a[i]);
	}
	sort(a+1,a+1+n);
	Init();
	Splay(1,0);
	while(q--)
	{
		rea(op);
		rea(k);
		if(op==1)
		{
			printf("%d\n",key[Get_kth(root,k+1)]);
		}
		else
		{
			change(k);
		}
	}
	return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值