BZOJ 3489: A simple rmq problem(主席树+二维线段树)

130 篇文章 1 订阅
92 篇文章 0 订阅

题目
三维偏序。
主席树套二维线段树。
namespace真舒服。
比KD树慢3倍。
AC Code:

#include<bits/stdc++.h>
#define maxn 100005
using namespace std;

int n,m,a[maxn],pre[maxn],loc[maxn];
vector<pair<int,int> >G[maxn];

namespace Seg2{
	#define maxppt maxn * 20 * 19
	int lc[maxppt] , rc[maxppt] , Max[maxppt] , tot;
	void Insert(int &now,int l,int r,const int &pos,const int &val){
		Max[++tot] = max(Max[now],val) , lc[tot] = lc[now] , rc[tot] = rc[now];
		now = tot;
		if(l == r) return;
		int mid = (l+r) >> 1;
		if(pos <= mid) Insert(lc[now],l,mid,pos,val);
		else Insert(rc[now],mid+1,r,pos,val);
	}
	int Query(int &now,int l,int r,const int &ql,const int &qr){
		if(!now || l>qr || ql>r) return 0;
		if(ql<=l && r<=qr) return Max[now];
		int mid = (l+r) >> 1;
		return max(Query(lc[now],l,mid,ql,qr),Query(rc[now],mid+1,r,ql,qr));
	}
}

namespace Seg1{
	#define maxpt maxn * 20
	int lc[maxpt] , rc[maxpt] , rt[maxpt] , tot;
	void Insert(int &now,int l,int r,const int &pos1,const int &pos2,const int &val){
		lc[++tot] = lc[now] , rc[tot] = rc[now] , rt[tot] = rt[now];
		now = tot;
		Seg2::Insert(rt[now],1,n+1,pos2,val);
		if(l == r) return;
		int mid = (l+r) >> 1;
		if(pos1 <= mid) Insert(lc[now],l,mid,pos1,pos2,val);
		else Insert(rc[now],mid+1,r,pos1,pos2,val);
	}
	int Query(int now,int l,int r,const int &ql,const int &qr,const int &ql2,const int &qr2){
		if(!now || l>qr || ql>r) return 0;
		if(ql<=l&& r<=qr) return Seg2::Query(rt[now],1,n+1,ql2,qr2);
		int mid = (l+r) >> 1;
		return max(Query(lc[now],l,mid,ql,qr,ql2,qr2),Query(rc[now],mid+1,r,ql,qr,ql2,qr2));
	}
}

int rt[maxn];

int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		pre[i] = loc[a[i]];
		loc[a[i]] = i;
		if(pre[i]) G[pre[pre[i]]].push_back(make_pair(pre[i],i));
	}
	for(int i=1;i<=n;i++) 
		if(loc[i])
			G[pre[loc[i]]].push_back(make_pair(loc[i],n+1));
	for(int i=0;i<=n;i++){
		if(i)rt[i] = rt[i-1];
		for(int j=0,siz=G[i].size();j<siz;j++)
			Seg1::Insert(rt[i],1,n+1,G[i][j].first,G[i][j].second,a[G[i][j].first]);
	}
	
	int la = 0;
	for(int x,y,l,r;m--;){
		scanf("%d%d",&x,&y);
		x = (x + la) % n + 1,
		y = (y + la) % n + 1;
		l = min(x,y) , r = max(x,y);
		printf("%d\n",la=Seg1::Query(rt[l-1],1,n+1,l,r,r+1,n+1));
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值