[Luogu 2073] 送花

<题目链接>

很容易想到的平衡树,加个维护区间和。

只需要插入和删除操作即可。

kth其实都不用的,最小和最大可以从根节点log n一直向左/一直向右跑到叶子节点而求得。

记得每插入完一个点一定要更新区间和!!更新区间和!!更新区间和!!

我就因为没更新,导致出来答案都是随机的,有时候对,有时候不对。

关于平衡树不多说啦,关于平衡树(Treap)的教程请看这里

上代码。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
const int MAXN=100010;
int n,w,x;
class Treap
{
	public:
		Treap(void)
		{
			rt=cnt=0;
			memset(a,0,sizeof a);
			memset(s,0,sizeof s);
		}
		void Insert(int w,int x)
		{
			_Insert(rt,w,x);
		}
		void Delete(bool l)
		{
			int i=Find(rt,l);
			_Delete(rt,s[i].w,s[i].v);
		}
		void Answer(void)
		{
			printf("%d %d",s[rt].bty,s[rt].val);
		}
	private:
		bool a[MAXN];
		int rt,cnt;
		struct node
		{
			int l,r,w,v,p,bty,val;
		}s[MAXN];
		int Random(void)
		{
			int x;
			while(a[x=rand()%MAXN]);
			a[x]=1;
			return x;
		}
		void Update(int i)
		{
			s[i].bty=s[s[i].l].bty+s[s[i].r].bty+s[i].w;
			s[i].val=s[s[i].l].val+s[s[i].r].val+s[i].v;
		}
		void L_Rotate(int &i)
		{
			int t=s[i].r;
			s[i].r=s[t].l,s[t].l=i;
			Update(i),Update(t),i=t;
		}
		void R_Rotate(int &i)
		{
			int t=s[i].l;
			s[i].l=s[t].r,s[t].r=i;
			Update(i),Update(t),i=t;
		}
		void _Insert(int &i,int w,int x)
		{
			if(!i)
			{
				s[i=++cnt].bty=s[i].w=w,s[i].val=s[i].v=x;
				s[i].p=Random();
				return;
			}
			if(x==s[i].v)
				return;
			if(x<s[i].v)
			{
				_Insert(s[i].l,w,x);
				if(s[s[i].l].p>s[i].p)
					R_Rotate(i);
			}
			else
			{
				_Insert(s[i].r,w,x);
				if(s[s[i].r].p>s[i].p)
					L_Rotate(i);
			}
			Update(i);//一定要更新!!
		}
		void _Delete(int &i,int w,int x)
		{
			if(!i)
				return;
			if(x==s[i].v)
			{
				if(!s[i].l || !s[i].r)
					i=s[i].l | s[i].r;
				else if(s[s[i].l].p>s[s[i].r].p)
					R_Rotate(i),_Delete(i,w,x);
				else
					L_Rotate(i),_Delete(i,w,x);
				return;
			}
			s[i].bty-=w,s[i].val-=x;
			if(x<s[i].v)
				_Delete(s[i].l,w,x);
			else
				_Delete(s[i].r,w,x);
		}
		int Find(int i,bool l)
		{
			if(l)
				while(s[i].l)
					i=s[i].l;
			else
				while(s[i].r)
					i=s[i].r;
			return i;
		}
}T;
int main(int argc,char *argv[])
{
	srand((unsigned)time(NULL));
	while(~scanf("%d",&n) && ~n)
		switch(n)
		{
			case 1:
				scanf("%d %d",&w,&x);
				T.Insert(w,x);
				break;
			case 2:
				T.Delete(0);
				break;
			case 3:
				T.Delete(1);
				break;
		}
	T.Answer();
	return 0;
}

谢谢阅读

posted @ 2017-12-21 18:11  Capella  阅读(146)  评论(0编辑  收藏  举报

谢谢光临