1. 程式人生 > >【莫隊】【連結串列】三校聯考1015T3

【莫隊】【連結串列】三校聯考1015T3

題意:

在這裡插入圖片描述


分析:

啊啊啊啊我發明的演算法居然以前有過。。。。https://blog.csdn.net/qq_34454069/article/details/80184286

方法其實很簡單。。。首先,把所有未加入的點放在一個雙向連結串列裡。

然後,每次插入一個值,就相當於把這個點從雙向連結串列中刪除。每次刪除的時候,統計一下其左側和右側的,已經從連結串列中刪去(即已經插入的)點的個數即可。

然而,問題來了,如果做莫隊的話。。有個小問題:插入值還好,但如果要刪除一個值,你就會把原來某個連續的區間,劃分為兩部分。然而這樣一來,你無法確定剩下的所有連續區間的最大長度。

所以,不能刪除的莫隊?就是我之前講的那個演算法(學名叫回滾莫隊)。

排序方式還是一樣的,只不過這裡對每個左端點在一個塊內的分別處理:
首先,先清空之前的狀態。
在這裡插入圖片描述
然後,右端點向右拓展直到某個詢問的右端點。
在這裡插入圖片描述
現在儲存所有當前答案。然後再依次插入左區間的點
在這裡插入圖片描述
得到答案後,再依次撤回操作(具體實現是通過棧暴力儲存每次修改的地方,參見程式碼)
再做下一次操作。
複雜度 O ( N N

) O(N\sqrt N)

#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]); }