题目链接:传送门
序列上的问题?想到莫队。
然而这题像bzoj4241 历史研究一样毒瘤,资瓷
O
(
1
)
O(1)
O(1)加入,不资瓷
O
(
1
)
O(1)
O(1)删除。
安利一波题解:bzoj4241 历史研究qwq
所以像4241一样,需要用到回滚莫队。
这里开两个数组
l
,
r
l,r
l,r,
l
[
i
]
l[i]
l[i]表示加入i时,
i
i
i到值域连续段左端有多少个数,
r
[
i
]
r[i]
r[i]表示加入i时,
i
i
i到值域连续段右端有多少个数。
加入一个数
x
x
x时,除了
l
[
x
]
,
r
[
x
]
l[x],r[x]
l[x],r[x]要修改,还要修改
x
x
x所在的值域连续段的左端和右端(以保证下一次更新不会出错)
然后就像回滚莫队的普通操作一样,对于每个块,求解左端点在块中的询问的答案,询问完后撤销左端点的操作。
因为这里加入一个数
x
x
x时不只更新了
l
[
x
]
l[x]
l[x]和
r
[
x
]
r[x]
r[x],所以要开一个栈保存更新了哪些位置和更新前的值。
然后撤销就大力
p
o
p
pop
pop就珂以了qwq。
毒瘤代码
P
s
.
Ps.
Ps.这段代码在
b
z
o
j
bzoj
bzoj上过了,本地也跑过了所有数据,但是在毒瘤
c
z
h
czh
czh的
O
J
OJ
OJ上就莫名爆
0
0
0 qwq
大概是
r
p
rp
rp又不够了,感觉可以从孟孙那里吸一些
r
p
rp
rp
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<math.h>
#define re register int
#define rl register ll
using namespace std;
typedef long long ll;
int read() {
re x=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9') {
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9') {
x=10*x+ch-'0';
ch=getchar();
}
return x*f;
}
namespace I_Love {
const int Size=200005;
int n,m,a[Size],belong[Size];
struct Query {
int id,l,r;
} Q[Size];
inline bool comp(Query x,Query y) {
if(belong[x.l]!=belong[y.l]) return belong[x.l]<belong[y.l];
return x.r<y.r;
}
int tmpl[Size],tmpr[Size],tp,stkl[Size],stkr[Size];
int Baoli(int l,int r) {
int nowmax=0;
for(re i=l; i<=r; i++) {
tmpr[a[i]]=tmpr[a[i]+1]+1;
tmpl[a[i]]=tmpl[a[i]-1]+1;
int now=tmpl[a[i]]+tmpr[a[i]]-1;
if(now>nowmax) {
nowmax=now;
}
//要更新a[i]所在的值域连续段的左右端点
tmpl[a[i]+tmpr[a[i]]-1]=now;
tmpr[a[i]-tmpl[a[i]]+1]=now;
//加到栈中
stkl[++tp]=a[i]+tmpr[a[i]]-1;
stkr[tp]=a[i]-tmpl[a[i]]+1;
stkl[++tp]=a[i];
stkr[tp]=a[i];
}
while(tp) {
tmpl[stkl[tp]]=tmpr[stkr[tp]]=0;
tp--;
}
return nowmax;
}
int lpos[Size],rpos[Size];
int ans,out[Size];
struct Stack {
int top;
int posL[Size],valL[Size];
int posR[Size],valR[Size];
inline void push_back(int x) {
top++;
posL[top]=x+rpos[x]-1;
valL[top]=lpos[posL[top]];
posR[top]=x-lpos[x]+1;
valR[top]=rpos[posR[top]];
}
} S;
void add(int x,bool flag) {
//flag表示要不要把当前修改过的东西放入栈里面以便之后撤销
lpos[x]=lpos[x-1]+1;
rpos[x]=rpos[x+1]+1;
int now=lpos[x]+rpos[x]-1;
if(now>ans) {
ans=now;
}
if(flag) {
S.push_back(x);
}
lpos[x+rpos[x]-1]=now;
rpos[x-lpos[x]+1]=now;
}
void del() {
int top=S.top;
lpos[S.posL[top]]=S.valL[top];
rpos[S.posR[top]]=S.valR[top];
S.top--;
}
void Fujibayashi_Ryou() {
n=read();
m=read();
int siz=sqrt(n);
for(re i=1; i<=n; i++) {
a[i]=read();
belong[i]=(i-1)/siz+1;
}
for(re i=1; i<=m; i++) {
Q[i].l=read();
Q[i].r=read();
Q[i].id=i;
}
sort(Q+1,Q+1+m,comp);
int num=belong[n],now=0;
for(re i=1; i<=num; i++) {
memset(lpos,0,sizeof(lpos));
memset(rpos,0,sizeof(rpos));
int blockR=min(siz*i,n);
int l=blockR+1,r=blockR;
ans=0;
for(re j=now+1; belong[Q[j].l]==i; j++) {
if(i==belong[Q[j].r]) {
//左右端点在一个块里就暴力
out[Q[j].id]=Baoli(Q[j].l,Q[j].r);
now=j;
continue;
}
//右边的操作是不用撤销的
while(r<Q[j].r) add(a[++r],0);
int pre=ans;
while(l>Q[j].l) add(a[--l],1);
out[Q[j].id]=ans;
while(S.top) del();
while(l<=blockR)
lpos[a[l]]=rpos[a[l++]]=0;
ans=pre;
now=j;
}
}
for(re i=1; i<=m; i++) {
printf("%d\n",out[i]);
}
}
}
int main() {
I_Love::Fujibayashi_Ryou();
return 0;
}
/*
9 3
2 4 3 6 1 5 8 9 7
3 5
2 6
1 4
*/