写了两个版本:
一个树套树
一个kdt
树套树版本并不能在bz ac。
因为内存占用达到了可耻的700mb,即便加了优化依旧在600mb左右
考虑实际上就是要在给定的
[l,r]
[
l
,
r
]
区间求出最大的数
使得
nxt[pos]<R pre[pos]<L
n
x
t
[
p
o
s
]
<
R
p
r
e
[
p
o
s
]
<
L
那么考虑预处理出每个点的
pre
p
r
e
nxt
n
x
t
那么在插入第pos个版本时,更新
[L,pos]
[
L
,
p
o
s
]
的值为
nxt
n
x
t
即可
查询时寻找第
L
L
这个点的最大值是否大于
很遗憾会
mle
m
l
e
…
c++代码如下:
#include<bits/stdc++.h>
#define rep(i,x,y) for(register int i = x ; i <= y; ++ i)
#define repd(i,x,y) for(register int i = x; i >= y; -- i)
using namespace std;
typedef long long ll;
template<typename T>inline bool chkmax(T&x,T y) { return x < y ? x = y,1:0; }
template<typename T>inline void read(T&x)
{
char c ;int sign = 1;x = 0;
do { c = getchar(); if(c == '-') sign = -1; }while(!isdigit(c));
do { x = x * 10 + c - '0'; c = getchar(); }while(isdigit(c));
x *= sign;
}
const int N = 1e5+500;
int rt[N],Ls[2000005],Rs[2000005];
int k[70000005],ls[70000005],rs[70000005],v[2000005];
int lst[N],p[N],q[N],a[N],lstans,sz,cnt,n,m;
int stk[500000],top;
bool add(int&rt,int y,int l,int r,int L,int R,int i)
{
rt = top ? stk[top--] : ++ cnt;
ls[rt] = ls[y]; rs[rt] = rs[y];
k[rt] = k[y];
if(k[rt] >= i)
{
stk[++top] = rt;
rt = y;
return true;
}
if(l == L && r == R)
{
chkmax(k[rt],i);
return false;
}
int mid = l + r >> 1;
if(L > mid)
{
if(add(rs[rt],rs[y],mid+1,r,L,R,i))
{
stk[++top] = rt;
rt = y;
return true;
}return false;
}
else if( R <= mid)
{
if(add(ls[rt],ls[y],l,mid,L,R,i))
{
stk[++top] = rt;
rt = y;
return true;
}return false;
}
else
{
bool e1 = add(ls[rt],ls[y],l,mid,L,mid,i);
bool e2 = add(rs[rt],rs[y],mid+1,r,mid+1,R,i);
if(e1 && e2)
{
stk[++top] = rt;
rt = y;
return true;
}return false;
}
}
void insert(int&rt,int y,int l,int r,int pos,int lst,int k,int w)
{
rt = ++ sz;
Ls[rt] = Ls[y];Rs[rt] = Rs[y];
add(v[rt],v[y],1,n,lst,k,w);
if(l == r) return ;
int mid = l + r>> 1;
if(pos <= mid) insert(Ls[rt],Ls[y],l,mid,pos,lst,k,w);
else insert(Rs[rt],Rs[y],mid+1,r,pos,lst,k,w);
}
bool check(int rt,int l,int r,int pos,int w)
{
if(k[rt] >= w) return true;
if(l == r||!rt) return false;
int mid = l + r >> 1;
if(pos <= mid) return check(ls[rt],l,mid,pos,w);
else return check(rs[rt],mid+1,r,pos,w);
}
int query(int x,int L,int R,int l,int r)
{
if(l == r) return l;
int mid = l + r >> 1;
if(check(v[Rs[x]],1,n,L,R) )
return query(Rs[x],L,R,mid+1,r);
else return query(Ls[x],L,R,l,mid);
}
int main()
{
freopen("7.in","r",stdin);
freopen("1.out","w",stdout);
read(n); read(m);
rep(i,1,n) read(a[i]);
rep(i,1,n) lst[i] = n + 1;
repd(i,n,1) p[i] = lst[a[i]],q[lst[a[i]]] = i,lst[a[i]] = i;
rep(i,1,n)
{
insert(rt[i],rt[i-1],0,n,a[i],q[i] + 1,i,p[i] - 1);
}
int x,y;
while(m -- )
{
read(x); read(y);
x = (x+lstans)%n+1; y = (y+lstans)%n+1;
if(x > y) swap(x,y);
printf("%d\n",lstans = query(rt[y],x,y ,0,n));
}
return 0;
}
只能换算法了,树套树我是不想再改了…
考虑
kdt
k
d
t
直接维护
nxt
n
x
t
pre
p
r
e
pos
p
o
s
即可
一顿瞎搞直接
ac
a
c
…
c++代码如下:
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#define rep(i,x,y) for(register int i = x ; i <= y; ++ i)
#define repd(i,x,y) for(register int i = x; i >= y; -- i)
using namespace std;
typedef long long ll;
template<typename T>inline bool chkmax(T&x,T y) { return x < y ? x = y,1:0; }
template<typename T>inline bool chkmin(T&x,T y) { return x > y ? x = y,1:0; }
template<typename T>inline void read(T&x)
{
char c ;int sign = 1;x = 0;
do { c = getchar(); if(c == '-') sign = -1; }while(!isdigit(c));
do { x = x * 10 + c - '0'; c = getchar(); }while(isdigit(c));
x *= sign;
}
const int N = 1e5+50;
int n,m,k,a[N],lst[N];
struct DATA { int pre,nxt,pos; }p[N];
const bool cmp(DATA a,DATA b)
{
if(k == 1) return a.pre < b.pre;
if(k == 2) return a.nxt < b.nxt;
if(k == 3) return a.pos < b.pos;
}
int ans,rt;
struct KD_TREE
{
DATA w[N];
int ls[N],rs[N];
int L,R,sz,mx[N][4],mi[N][4],val[N];
inline void pre() { memset(mi,0x3f,sizeof mi); }
inline void update(int rt)
{
val[rt] = a[w[rt].pos];
mi[rt][1] = w[rt].pre;
mx[rt][2] = w[rt].nxt;
mx[rt][3] = mi[rt][3] = w[rt].pos;
if(rs[rt])
{
chkmax(val[rt],val[rs[rt]]);
chkmax(mx[rt][2],mx[rs[rt]][2]);
chkmax(mx[rt][3],mx[rs[rt]][3]);
chkmin(mi[rt][1],mi[rs[rt]][1]);
chkmin(mi[rt][3],mi[rs[rt]][3]);
}
if(ls[rt])
{
chkmax(val[rt],val[ls[rt]]);
chkmax(mx[rt][2],mx[ls[rt]][2]);
chkmax(mx[rt][3],mx[ls[rt]][3]);
chkmin(mi[rt][1],mi[ls[rt]][1]);
chkmin(mi[rt][3],mi[ls[rt]][3]);
}
}
void build(int&rt,int l,int r)
{
int mid = l + r>>1;
nth_element(p+l,p+mid,p+r+1,cmp);
w[rt = ++sz] = p[mid];
k = (k+1)%3+1;
if(l < mid) build(ls[rt],l,mid-1);
if(r > mid) build(rs[rt],mid+1,r);
update(rt);
}
inline int find(int rt)
{
if(mi[rt][1] >= L || mx[rt][2] <= R || mi[rt][3] > R || mx[rt][3] < L) return -1;
return val[rt];
}
void query(int rt)
{
if(w[rt].pre < L && w[rt].nxt > R && w[rt].pos <= R && w[rt].pos >= L)
ans = max(ans,a[w[rt].pos]);
int dl = find(ls[rt]);
int dr = find(rs[rt]);
if(dl < dr)
{
if(~dr && dr > ans) query(rs[rt]);
if(~dl && dl > ans) query(ls[rt]);
}
else
{
if(~dl && dl > ans) query(ls[rt]);
if(~dr && dr > ans) query(rs[rt]);
}
}
}kd;
int main()
{
read(n); read(m);
rep(i,1,n) read(a[i]);
rep(i,1,n) lst[i] = n + 1;
repd(i,n,1)
{
p[i].nxt = lst[a[i]];
p[lst[a[i]]].pre = i;
p[i].pos = i;
lst[a[i]] = i;
}
k = 1;
kd.build(rt,1,n);
while(m -- )
{
int x,y;
read(x); read(y);
x = (x+ans)%n+1; y = (y+ans)%n+1;
if(x > y) swap(x,y);
ans = 0; kd.L = x; kd.R = y;
kd.query(rt);
printf("%d\n",ans);
}
return 0;
}