【莫隊】【連結串列】三校聯考1015T3
阿新 • • 發佈:2018-11-07
題意:
分析:
啊啊啊啊我發明的演算法居然以前有過。。。。https://blog.csdn.net/qq_34454069/article/details/80184286
方法其實很簡單。。。首先,把所有未加入的點放在一個雙向連結串列裡。
然後,每次插入一個值,就相當於把這個點從雙向連結串列中刪除。每次刪除的時候,統計一下其左側和右側的,已經從連結串列中刪去(即已經插入的)點的個數即可。
然而,問題來了,如果做莫隊的話。。有個小問題:插入值還好,但如果要刪除一個值,你就會把原來某個連續的區間,劃分為兩部分。然而這樣一來,你無法確定剩下的所有連續區間的最大長度。
所以,不能刪除的莫隊?就是我之前講的那個演算法(學名叫回滾莫隊)。
排序方式還是一樣的,只不過這裡對每個左端點在一個塊內的分別處理:
首先,先清空之前的狀態。
然後,右端點向右拓展直到某個詢問的右端點。
現在儲存所有當前答案。然後再依次插入左區間的點
得到答案後,再依次撤回操作(具體實現是通過棧暴力儲存每次修改的地方,參見程式碼)
再做下一次操作。
複雜度
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<stack>
#define MAXN 100010
#define SF scanf
#define PF printf
using namespace std;
typedef pair<int,int> pii;
int a[MAXN],blo[MAXN];
int ans[MAXN],ansx;
struct node{
int l,r,id;
bool operator <(const node &a) const{
if(blo[l]!=blo[a.l])
return blo[l]<blo[a.l];
return r<a.r;
}
}q[MAXN];
int lp[MAXN],rp[MAXN];
struct chag{
int l,orgl;
int r,orgr;
chag () {}
chag (int l1,int ol1,int r1,int or1):l(l1),orgl(ol1),r(r1),orgr(or1) {}
};
stack<chag> s;
void add(int x,bool flag){
int sizl=x-lp[x]-1;
int sizr=rp[x]-x-1;
ansx=max(ansx,sizl+sizr+1);
if(flag)
s.push(chag(lp[x],rp[lp[x]],rp[x],lp[rp[x]]));
rp[lp[x]]=rp[x];
lp[rp[x]]=lp[x];
}
void restore(){
while(!s.empty()){
int l=s.top().l;
int r=s.top().r;
int orgl=s.top().orgl;
int orgr=s.top().orgr;
rp[l]=orgl;
lp[r]=orgr;
s.pop();
}
}
int n,m;
void solve(int lasx,int L,int R){
int las=lasx-1;
for(int i=1;i<=n;i++){
lp[i]=i-1;
rp[i]=i+1;
}
ansx=0;
while(q[L].r<lasx&&L<=R){
for(int i=q[L].l;i<=q[L].r;i++)
add(a[i],1);
ans[q[L].id]=ansx;
restore();
ansx=0;
L++;
}
for(int i=L;i<=R;i++){
while(las<q[i].r)
add(a[++las],0);
int pans=ansx;
for(int j=lasx-1;j>=q[i].l;j--)
add(a[j],1);
ans[q[i].id]=ansx;
restore();
ansx=pans;
}
}
int main(){
freopen("ants.in","r",stdin);
freopen("ants.out","w",stdout);
SF("%d%d",&n,&m);
for(int i=1;i<=n;i++)
SF("%d",&a[i]);
for(int i=1;i<=m;i++){
SF("%d%d",&q[i].l,&q[i].r);
q[i].id=i;
}
int BASE=int(sqrt(n));
for(int i=1;i<=n;i++)
blo[i]=i/BASE+1;
sort(q+1,q+1+m);
int las=1;
for(int i=2;i<=m;i++)
if(blo[q[i].l]!=blo[q[i-1].l]){
solve(blo[q[i-1].l]*BASE,las,i-1);
las=i;
}
solve(blo[q[las].l]*BASE,las,m);
for(int i=1;i<=m;i++)
PF("%d\n",ans[i]);
}