[bzoj4358] permu
强行上莫队+线段树显然是会T的。
如果莫队没有删除的转移的话...就可以用并查集代替线段树。
所以按照一般姿势将询问排序好后,右端点照常,左端点每次从左端点所属块的末端开始跑,跑完后暴力撤回。
复杂度还是O(m*n^0.5)
为了能够撤回,并查集合并的时候,以临时增加的点为父亲。
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 const int maxn=50233; 8 struct zs{int l,r,id;}q[maxn]; 9 int fa[maxn],sz[maxn],mp[maxn],st[maxn],top; 10 int B[maxn],An[maxn]; 11 int i,j,k,n,m,ans; 12 13 int ra;char rx; 14 inline int read(){ 15 rx=getchar(),ra=0; 16 while(rx<'0'||rx>'9')rx=getchar(); 17 while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra; 18 } 19 20 inline int getfa(int x){return fa[x]!=x?fa[x]=getfa(fa[x]):x;} 21 inline int get1(int x){while(fa[x]!=x)x=fa[x];return x;} 22 23 inline void add(int x){ 24 sz[x]=1; 25 int pre=getfa(x-1),aft=getfa(x+1); 26 if(sz[pre])sz[pre]+=sz[x],fa[x]=pre,x=pre; 27 if(sz[aft])sz[aft]+=sz[x],fa[x]=aft,x=aft; 28 if(sz[x]>ans)ans=sz[x]; 29 } 30 inline void add2(int x){ 31 sz[x]=1; 32 int pre=get1(x-1),aft=get1(x+1); 33 34 if(sz[pre]) 35 sz[x]+=sz[pre],fa[pre]=x,st[++top]=pre; 36 if(sz[aft]) 37 sz[x]+=sz[aft],fa[aft]=x,st[++top]=aft; 38 if(sz[x]>ans)ans=sz[x]; 39 } 40 41 bool cmp(zs a,zs b){return B[a.l]<B[b.l]||(B[a.l]==B[b.l]&&a.r<b.r);} 42 43 int main(){ 44 n=read(),m=read();int kuai=(int)sqrt(n*1.2)+3; 45 for(i=1;i<=n;i++)mp[i]=read(),B[i]=(i+kuai-1)/kuai; 46 for(i=1;i<=m;i++)q[i].l=read(),q[i].r=read(),q[i].id=i; 47 sort(q+1,q+1+m,cmp); 48 int r,r1,now,tmp; 49 for(i=1;i<=m;){ 50 for(r=i;B[q[r].l]==B[q[i].l];r++);r--; 51 r1=B[q[i].l]==B[n]?n:B[q[i].l]*kuai; 52 for(j=0;j<=n+1;j++)fa[j]=j,sz[j]=0; 53 ans=0,now=r1+1; 54 55 for(j=i;j<=r;j++){ 56 while(now<=q[j].r)add(mp[now++]); 57 tmp=ans,top=0; 58 for(k=q[j].l;k<=q[j].r&&k<=r1;k++)add2(mp[k]); 59 An[q[j].id]=ans; 60 while(top)fa[st[top]]=st[top],top--; 61 for(k=q[j].l;k<=q[j].r&&k<=r1;k++)fa[mp[k]]=mp[k],sz[mp[k]]=0; 62 ans=tmp; 63 } 64 i=r+1; 65 } 66 for(i=1;i<=m;i++)printf("%d\n",An[i]); 67 }