回滚莫队的精髓在于撤销。
本题要记录一个子树最小值,所以要用 vector
存路径,再倒序还原回去。 然后用
l
a
s
t
a
n
s
lastans
lastans 记录上次询问答案。
注意回收
T
r
i
e
Trie
Trie 树上的节点。常数会小一些。
时间复杂度
O
(
(
n
+
m
)
n
l
o
g
n
)
O((n+m)\sqrt{n}logn)
O((n+m)n
logn) 。跑了 1700ms 。
#include <cstdio>
#include <bitset>
#include <algorithm>
#include <iostream>
#include <bits/stdc++.h>
#include <cstring>
#define INF 0x3f3f3f3f
#define PII pair<int,int>
#define PIII pair<int,PII>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int Maxn=5*1e4;
const int Maxm=5*1e3;
const int Maxa=1e6;
const int Maxk=20;
int n,m,block,bl[Maxn+5],a[Maxn+5],xo[Maxa+5],L[Maxn+5],R[Maxn+5];
int res[Maxm+5];
struct qry{
int l,r,id;
bool operator <(const qry &a) const {
return (bl[l]==bl[a.l])?r<a.r:l<a.l;
}
}q[Maxm+5];
struct Trie_Tree{
int Trie[Maxn*Maxk+5][2];
int _max[Maxn*Maxk+5],_min[Maxn*Maxk+5];
int sz1,sz2;
PIII used[Maxn*Maxk+5];
void Insert1(int x) {
int it=1,val=xo[x-1];
for(int i=19;i>=0;i--) {
int d=val>>i&1;
if(!Trie[it][d]) Trie[it][d]=++sz2,_min[sz2]=INF,_max[sz2]=-INF;
it=Trie[it][d];
used[++sz1]=make_pair(it,make_pair(_min[it],_max[it]));
_min[it]=min(_min[it],x);
_max[it]=max(_max[it],x);
}
}
void Insert2(int x) {
int it=1,val=xo[x];
for(int i=19;i>=0;i--) {
int d=val>>i&1;
if(!Trie[it][d]) Trie[it][d]=++sz2,_min[sz2]=INF,_max[sz2]=-INF;
it=Trie[it][d];
used[++sz1]=make_pair(it,make_pair(_min[it],_max[it]));
_min[it]=min(_min[it],x);
_max[it]=max(_max[it],x);
}
}
int Query1(int x) {
int it=1,tot=0,val=xo[x];
for(int i=19;i>=0;i--) {
int d=val>>i&1;
if(_min[Trie[it][d^1]]<=x) {
tot+=1<<i;
it=Trie[it][d^1];
}
else it=Trie[it][d];
}
return tot;
}
int Query2(int x) {
int it=1,tot=0,val=xo[x-1];
for(int i=19;i>=0;i--) {
int d=val>>i&1;
if(_max[Trie[it][d^1]]>=x) {
tot+=1<<i;
it=Trie[it][d^1];
}
else it=Trie[it][d];
}
return tot;
}
void Clear1() {
for(int i=sz1;i>=1;i--) {
_min[used[i].first]=used[i].second.first;
_max[used[i].first]=used[i].second.second;
}
sz1=0;
}
void Clear2() {
_min[0]=INF,_max[0]=-INF;
for(int i=1;i<=sz2;i++) {
Trie[i][0]=Trie[i][1]=0;
}
sz2=1;
}
}T1,T2;
signed main() {
scanf("%d%d",&n,&m); block=max(1,(int)sqrt(1ll*n*n/m));
for(int i=1;i<=1e6;i++) xo[i]=xo[i-1]^i;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) bl[i]=(i-1)/block+1;
for(int i=1;i<=bl[n];i++) {
L[i]=(i-1)*block+1,R[i]=min(n,i*block);
}
for(int i=1;i<=m;i++) {
scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
}
sort(q+1,q+1+m);
int l,r,lastans,ans;
for(int i=1;i<=m;i++) {
int x=bl[q[i].l];
if(x!=bl[q[i-1].l]) {
T1.Clear2(); T2.Clear2();
l=R[x]+1,r=R[x],lastans=0;
}
if(bl[q[i].l]==bl[q[i].r]) {
ans=0;
for(int j=q[i].l;j<=q[i].r;j++) {
T1.Insert1(a[j]);
T2.Insert2(a[j]);
ans=max({ans,T1.Query1(a[j]),T2.Query2(a[j])});
}
res[q[i].id]=ans;
T1.Clear2(); T2.Clear2();
continue;
}
while(r<q[i].r) {
r++;
T1.Insert1(a[r]);
T2.Insert2(a[r]);
lastans=max({lastans,T1.Query1(a[r]),T2.Query2(a[r])});
}
T1.sz1=T2.sz1=0;
ans=lastans;
while(l>q[i].l) {
l--;
T1.Insert1(a[l]);
T2.Insert2(a[l]);
ans=max({ans,T1.Query1(a[l]),T2.Query2(a[l])});
}
res[q[i].id]=ans;
T1.Clear1(),T2.Clear1();
l=R[x]+1;
}
for(int i=1;i<=m;i++) {
printf("%d\n",res[i]);
}
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」