• BZOJ3489:A simple rmq problem


    浅谈主席树:https://www.cnblogs.com/AKMer/p/9956734.html

    题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=3489

    题目意思就是在线求(pos)([l,r])(lst)([0,l-1])(nxt)([r+1,n+1])的点中权值最大的。其中(pos)表示这个点的下标,(lst)表示上一个跟这个点相同的点的下标,(nxt)表示下一个跟这个点相同的点的下标。

    这样子就变成求立方体最大点值了,我们可以果断树套树套树走一波,然后获得(TLE)的好成绩。

    所以我们得用一些神奇的手段降低问题的维度。

    而这个手段就是可持久化。

    我们按(lst)从小到大在(nxt)值域范围内建立可持久化线段树,内套位置线段树维护区间最大值即可。

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

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

    代码如下:

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    
    const int maxn=1e5+5;
    
    int n,m,lstans;
    int rt[maxn],tmp[maxn];
    int pos[maxn],a[maxn],lst[maxn],nxt[maxn];
    
    int read() {
    	int x=0,f=1;char ch=getchar();
    	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    	for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    	return x*f;
    }
    
    struct Project {
    	int lst,nxt,pos,val;
    
    	Project() {}
    
    	Project(int _lst,int _nxt,int _pos,int _val) {
    		lst=_lst,nxt=_nxt,pos=_pos,val=_val;
    	}
    
    	bool operator<(const Project &a)const {
    		return lst<a.lst;
    	}
    }p[maxn];
    
    struct pos_chairman_tree {
    	int tot;
    	struct tree_node {
    		int ls,rs,mx;
    	}tree[maxn*18*18];
    
    	void change(int &p,int lst,int l,int r,Project node) {
    		p=++tot;tree[p]=tree[lst];
    		tree[p].mx=max(tree[p].mx,node.val);
    		if(l==r)return;
    		int mid=(l+r)>>1;
    		if(node.pos<=mid)change(tree[p].ls,tree[lst].ls,l,mid,node);
    		else change(tree[p].rs,tree[lst].rs,mid+1,r,node);
    	}
    
    	int query(int p,int l,int r,int L,int R) {
    		if(L<=l&&r<=R)return tree[p].mx;
    		int mid=(l+r)>>1,res=0;
    		if(L<=mid)res=max(res,query(tree[p].ls,l,mid,L,R));
    		if(R>mid)res=max(res,query(tree[p].rs,mid+1,r,L,R));
    		return res;
    	}
    }T2;
    
    struct lst_chairman_tree {
    	int tot;
    	struct tree_node {
    		int ls,rs,rt;
    	}tree[maxn*18];
    
    	void change(int &p,int lst,int l,int r,Project node) {
    		p=++tot;tree[p]=tree[lst];
    		T2.change(tree[p].rt,tree[lst].rt,1,n,node);
    		if(l==r)return;
    		int mid=(l+r)>>1;
    		if(node.nxt<=mid)change(tree[p].ls,tree[lst].ls,l,mid,node);
    		else change(tree[p].rs,tree[lst].rs,mid+1,r,node);
    	}
    
    	int query(int p,int l,int r,int L,int R) {
    		if(!p)return 0;
    		if(l>R)return T2.query(tree[p].rt,1,n,L,R);
    		int mid=(l+r)>>1,res=query(tree[p].rs,mid+1,r,L,R);
    		if(R+1<=mid)res=max(res,query(tree[p].ls,l,mid,L,R));
    		return res;
    	}
    }T1;
    
    int main() {
    	n=read(),m=read();
    	for(int i=1;i<=n;i++)
    		a[i]=read(),lst[i]=pos[a[i]],pos[a[i]]=i;
    	for(int i=1;i<=n;i++)pos[i]=n+1;
    	for(int i=n;i;i--)nxt[i]=pos[a[i]],pos[a[i]]=i;
    	for(int i=1;i<=n;i++)p[i]=Project(lst[i],nxt[i],i,a[i]);
    	sort(p+1,p+n+1);
    	for(int i=1;i<=n;i++) {
    		tmp[i]=p[i].lst;
    		T1.change(rt[i],rt[i-1],2,n+1,p[i]);
    	}
    	for(int i=1;i<=m;i++) {
    		int l=(read()+lstans)%n+1,r=(read()+lstans)%n+1;
    		if(r<l)swap(l,r);
    		int pos=lower_bound(tmp+1,tmp+n+1,l)-tmp-1;
    		lstans=T1.query(rt[pos],2,n+1,l,r);
    		printf("%d
    ",lstans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    SQL学习日志
    程序员之路──如何学习C语言并精通C语言
    using用法
    c#中的接口与类的区别
    用c#来实现一种行列式的计算优化
    python 切换目录
    如何光盘自动运行html?
    nsis 安装脚本示例(转)
    python sys.path.append
    python 面向对象初认识
  • 原文地址:https://www.cnblogs.com/AKMer/p/10197640.html
Copyright © 2020-2023  润新知