zoukankan      html  css  js  c++  java
  • [Luogu 1168] 中位数

    <题目链接>

    中位数可以转化为区间第k大问题,当然是选择Treap实现名次树了啊。(笑)

    功能十分简单的Treap即能满足需求——只需要插入与查找第大的功能。

    插入第i个数时,如果i是奇数,随即询问当前排名第(i+1>>1)的数。

    注意是一边插入一边询问,这样可以保留原序列的顺序,而不是所有插入完后再询问。

    这样一趟下来,所有数都插入完毕了,询问也处理完毕了。

    封装版代码

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <ctime>
    const int MAXN=100010;
    int n;
    class Treap
    {
    	public:
    		Treap(void)
    		{
    			rt=cnt=0;
    			memset(a,0,sizeof a);
    			memset(s,0,sizeof s);
    		}
    		void Insert(int x)
    		{
    			_Insert(rt,x);
    		}
    		int Xth(int x)
    		{
    			return _Xth(rt,x);
    		}
    	private:
    		bool a[MAXN];
    		int rt,cnt;
    		struct node
    		{
    			int l,r,v,p,size,num;
    		}s[MAXN];
    		int Random(void)
    		{
    			int x;
    			while(a[x=rand()%MAXN]);
    			a[x]=1;
    			return x;
    		}
    		void Update(int i)
    		{
    			s[i].size=s[s[i].l].size+s[s[i].r].size+s[i].num;
    		}
    		void L_Rotate(int &i)
    		{
    			int t=s[i].r;
    			s[i].r=s[t].l,s[t].l=i;
    			s[t].size=s[i].size;
    			Update(i),i=t;
    		}
    		void R_Rotate(int &i)
    		{
    			int t=s[i].l;
    			s[i].l=s[t].r,s[t].r=i;
    			s[t].size=s[i].size;
    			Update(i),i=t;
    		}
    		void _Insert(int &i,int x)
    		{
    			if(!i)
    			{
    				s[i=++cnt].v=x,s[i].p=Random();
    				s[i].size=s[i].num=1;
    				return;
    			}
    			++s[i].size;
    			if(x==s[i].v)
    				++s[i].num;
    			else if(x<s[i].v)
    			{
    				_Insert(s[i].l,x);	
    				if(s[s[i].l].p>s[i].p)
    				    R_Rotate(i);
    			}
    			else
    			{
    				_Insert(s[i].r,x);
    				if(s[s[i].r].p>s[i].p)
    					L_Rotate(i);
    			}
    		}
    		int _Xth(int i,int x)
    		{
    			if(!i)
    				return 0;
    			int t;
    			if(x<=s[s[i].l].size)
    				return _Xth(s[i].l,x);
    			else if(x>(t=s[s[i].l].size+s[i].num))
    				return _Xth(s[i].r,x-t);
    			else
    				return s[i].v;
    		}
    }T;
    int main(int argc,char *argv[])
    {
    	scanf("%d",&n);
    	srand((unsigned)time(NULL));
    	for(int i=1,x;i<=n;++i)
    	{
    		scanf("%d",&x);
    		T.Insert(x);
    		if(i&1)
    			printf("%d
    ",T.Xth(i+1>>1));
    	}
    	return 0;
    }
    

    精简版代码

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <ctime>
    const int MAXN=100010;
    bool a[MAXN];
    int n,rt,cnt;
    struct node
    {
    	int l,r,v,p,size,num;
    }s[MAXN];
    int Random(void)
    {
    	int x;
    	while(a[x=rand()%MAXN]);
    	a[x]=1;
    	return x;
    }
    void Update(int i)
    {
    	s[i].size=s[s[i].l].size+s[s[i].r].size+s[i].num;
    }
    void L_Rotate(int &i)
    {
    	int t=s[i].r;
    	s[i].r=s[t].l,s[t].l=i;
    	s[t].size=s[i].size;
    	Update(i),i=t;
    }
    void R_Rotate(int &i)
    {
    	int t=s[i].l;
    	s[i].l=s[t].r,s[t].r=i;
    	s[t].size=s[i].size;
    	Update(i),i=t;
    }
    void Insert(int &i,int x)
    {
    	if(!i)
    	{
    		s[i=++cnt].v=x,s[i].p=Random();
    		s[i].size=s[i].num=1;
    		return;
    	}
    	++s[i].size;
    	if(x==s[i].v)
    		++s[i].num;
    	else if(x<s[i].v)
    	{
    		Insert(s[i].l,x);
    		if(s[s[i].l].p>s[i].p)
    			R_Rotate(i);
    	}
    	else
    	{
    		Insert(s[i].r,x);
    		if(s[s[i].r].p>s[i].p)
    			L_Rotate(i);
    	}
    }
    int Xth(int i,int x)
    {
    	if(!i)
    		return 0;
    	int t;
    	if(x<=s[s[i].l].size)
    		return Xth(s[i].l,x);
    	else if(x>(t=s[s[i].l].size+s[i].num))
    		return Xth(s[i].r,x-t);
    	else
    		return s[i].v;
    }
    int main(int argc,char *argv[])
    {
    	scanf("%d",&n);
    	srand((unsigned)time(NULL));
    	for(int i=1,x;i<=n;++i)
    	{
    		scanf("%d",&x);
    		Insert(rt,x);
    		if(i&1)
    			printf("%d
    ",Xth(rt,i+1>>1));
    	}
    	return 0;
    }
    

    谢谢阅读。

  • 相关阅读:
    数论
    2019牛客暑期多校训练营(第七场)
    C++大数模板
    网络流
    2019 Multi-University Training Contest 6
    无聊的数列
    Can you answer on these queries III
    Interval GCD
    2733:判断闰年-poj
    题目1083:特殊乘法-九度oj
  • 原文地址:https://www.cnblogs.com/Capella/p/8072763.html
Copyright © 2011-2022 走看看