BZOJ 3489 A simple rmq problem 可持久化树套树

题目大意:给定一个序列,多次询问某一区间中出现且仅出现一次的最大的数

令第i个数左侧第一个与这个数相同的数为last[i] 右侧第一个与这个相同的数为next[i]

那么一个数a[i]在区间内出现一次当且仅当last[i]<l&&next[i]>r&&l<=i<=r

于是我们将元素按照last[i]排序并构建可持久化线段树 令pos为满足last[i]<l的最大的i

每次查询我要查询的是第pos个版本的线段树内所有next[i]>r的数中[l,r]区间内的最大值

因此我们外层线段树维护next 每个节点开一棵可持久化线段树维护相应位置元素的最大值

每次插入一个点的时候,先依照外层线段树的上一个版本新建一条链

然后链上的每个节点根据上一个版本该节点的内层线段树构建这个节点的内层线段树 同样只需要新建一条链

查询就按照正常树套树查询即可

时间复杂度O(mlog^2n) 空间复杂度O(nlog^2n)

记得开内存池 否则TLE

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 100100
using namespace std;
struct element{
	int num,next,last,pos;
	bool operator < (const element &e) const
	{
		return last < e.last ;
	}
	bool operator < (int x) const
	{
		return last < x ;
	}
}a[M];
int n,m,last_ans;
int pos[M];
struct Segtree{
	Segtree *ls,*rs;
	int max_num;
	void* operator new (size_t,Segtree *_,Segtree *__,int ___)
	{
		static Segtree mempool[35000000],*C=mempool;
		C->ls=_;
		C->rs=__;
		C->max_num=___;
		return C++;
	}
	Segtree* Build_Tree(int x,int y,int pos,int val)
	{
		int mid=x+y>>1;
		if(x==y)
			return new (0x0,0x0,max(max_num,val) ) Segtree;
		if(pos<=mid)
			return new (ls->Build_Tree(x,mid,pos,val),rs,max(max_num,val) ) Segtree;
		else
			return new (ls,rs->Build_Tree(mid+1,y,pos,val),max(max_num,val) ) Segtree;
	}
	int Query(int x,int y,int l,int r)
	{
		int mid=x+y>>1;
		if(max_num==0)
			return 0;
		if(x==l&&y==r)
			return max_num;
		if(r<=mid)
			return ls->Query(x,mid,l,r);
		if(l>mid)
			return rs->Query(mid+1,y,l,r);
		return max( ls->Query(x,mid,l,mid) , rs->Query(mid+1,y,mid+1,r) );
	}
};
struct abcd{
	abcd *ls,*rs;
	Segtree *tree;
	void* operator new (size_t,abcd *_,abcd *__,Segtree *___)
	{
		static abcd mempool[2000000],*C=mempool;
		C->ls=_;
		C->rs=__;
		C->tree=___;
		return C++;
	}
	abcd* Build_Tree(int x,int y,int pos,int val,int _pos)
	{
		int mid=x+y>>1;
		if(x==y) return new (0x0,0x0,tree->Build_Tree(1,n,_pos,val)) abcd;
		if(pos<=mid)
			return new (ls->Build_Tree(x,mid,pos,val,_pos),rs,tree->Build_Tree(1,n,_pos,val)) abcd;
		else
			return new (ls,rs->Build_Tree(mid+1,y,pos,val,_pos),tree->Build_Tree(1,n,_pos,val)) abcd;
	}
	int Query(int x,int y,int pos,int l,int r)
	{
		int mid=x+y>>1;
		if(x==y)
			return tree->Query(1,n,l,r);
		if(pos>mid)
			return rs->Query(mid+1,y,pos,l,r);
		else
			return max(ls->Query(x,mid,pos,l,r),rs->tree->Query(1,n,l,r));
	}
}*tree[M];
void Initialize()
{
	tree[0]=new (0x0,0x0,new (0x0,0x0,0) Segtree) abcd ;
	tree[0]->ls=tree[0]->rs=tree[0];
	tree[0]->tree->ls=tree[0]->tree->rs=tree[0]->tree;
}
namespace IStream{
    const int L=1<<15;  
    char buffer[L],*S,*T;  
    inline char Get_Char()  
    {  
        if(S==T)  
        {  
            T=(S=buffer)+fread(buffer,1,L,stdin);  
            if(S==T) return EOF;  
        }  
        return *S++;  
    }  
    inline int Get_Int()  
    {  
        char c;  
        int re=0;  
        for(c=Get_Char();c<'0'||c>'9';c=Get_Char());  
        while(c>='0'&&c<='9')  
            re=(re<<1)+(re<<3)+(c-'0'),c=Get_Char();  
        return re;  
    }  
}  
class OStream{  
    private:  
        static const int L=1<<15;  
        char stack[20];int top;  
        char buffer[L],*S;  
    public:  
        OStream()  
        {  
            S=buffer;  
        }  
        void Put_Int(int x)  
        {  
            stack[++top]='\n';  
            if(!x) stack[++top]='0';  
            else while(x)  
                stack[++top]=x%10+'0',x/=10;  
            while(top)  
            {  
                if(S==buffer+L-1)  
                {  
                    printf("%s",buffer);  
                    S=buffer;  
                }  
                *S++=stack[top--];  
            }  
        }  
        ~OStream()  
        {  
            *S=0;  
            puts(buffer);  
        }  
}os;
int main()
{
	int i,x,y;
	cin>>n>>m;
	Initialize();
	for(i=1;i<=n;i++)
	{
		a[i].num=IStream::Get_Int();
		a[i].next=n+1;
		if(pos[a[i].num])
		{
			a[pos[a[i].num]].next=i;
			a[i].last=pos[a[i].num];
		}
		else
			a[i].last=0;
		pos[a[i].num]=i;
		a[i].pos=i;
	}
	sort(a+1,a+n+1);
	for(i=1;i<=n;i++)
		tree[i]=tree[i-1]->Build_Tree(0,n+1,a[i].next,a[i].num,a[i].pos);
	for(i=1;i<=m;i++)
	{
		x=IStream::Get_Int();
		y=IStream::Get_Int();
		int l=min((x+last_ans)%n+1,(y+last_ans)%n+1);
		int r=max((x+last_ans)%n+1,(y+last_ans)%n+1);
		int pos=lower_bound(a+1,a+n+1,l)-1-a;
		os.Put_Int( last_ans=tree[pos]->Query(0,n+1,r+1,l,r) );
	}
	return 0;
}


你可能感兴趣的:(bzoj,树套树,可持久化线段树,BZOJ3489,可持久化树套树)