bzoj 4358: permu 莫队
第一步先莫队分块。
对于每一块l~r,初始右端点设为r+1,然后每个询问先将右端点往右移,然后处理询问在l~r之间的部分,最后用一个栈再把l~r的复原。
具体来说是维护两个数组now1和now2,一个向右最长的长度,一个向左的长度,每插入一个值x,用x+1的now2更新x的now2,用x-1的now1更新x的now1,now1[x]+now2[x]-1可能为最终答案,再把x所在的最长区间的左右端点的now数组更新,中间的值不需要更新,因为不可能再往中间插入数了。
有生以来第一次bzoj榜一。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #define N 50005 6 #define d 223 7 using namespace std; 8 int n,m; 9 int c[N]; 10 int ans[N]; 11 struct node 12 { 13 int l,r,id,yuan; 14 friend bool operator < (node aa,node bb) 15 { 16 if(aa.id!=bb.id)return aa.id<bb.id; 17 return aa.r<bb.r; 18 } 19 }a[N]; 20 int now1[N],now2[N]; 21 int st1[N*2],st2[N*2],top; 22 int main() 23 { 24 scanf("%d%d",&n,&m); 25 for(int i=1;i<=n;i++)scanf("%d",&c[i]); 26 for(int i=1;i<=m;i++) 27 { 28 scanf("%d%d",&a[i].l,&a[i].r); 29 a[i].yuan=i;a[i].id=(a[i].l-1)/d+1; 30 } 31 sort(a+1,a+m+1); 32 int as=0;int r=0,t=0; 33 for(int i=1;i<=m;i++) 34 { 35 if(a[i].id!=a[i-1].id) 36 { 37 as=0; 38 memset(now1,0,sizeof(now1)); 39 memset(now2,0,sizeof(now2)); 40 r=t=a[i].id*d; 41 } 42 while(a[i].r>r) 43 { 44 r++; 45 now1[c[r]]=now1[c[r]+1]+1; 46 now2[c[r]]=now2[c[r]-1]+1; 47 int tt=now1[c[r]]+now2[c[r]]-1; 48 now2[c[r]+now1[c[r]]-1]=tt; 49 now1[c[r]-now2[c[r]]+1]=tt; 50 as=max(as,tt); 51 } 52 int tmp=as;top=0; 53 for(int j=a[i].l;j<=min(a[i].r,t);j++) 54 { 55 now1[c[j]]=now1[c[j]+1]+1; 56 now2[c[j]]=now2[c[j]-1]+1; 57 int tt=now1[c[j]]+now2[c[j]]-1; 58 int rr=c[j]+now1[c[j]]-1;int ll=c[j]-now2[c[j]]+1; 59 st1[++top]=rr;st2[top]=now2[rr]; 60 st1[++top]=ll;st2[top]=now1[ll]; 61 now2[rr]=tt; 62 now1[ll]=tt; 63 tmp=max(tmp,tt); 64 } 65 for(int j=top;j>=1;j--) 66 { 67 if(j%2==0)now1[st1[j]]=st2[j]; 68 else now2[st1[j]]=st2[j]; 69 } 70 for(int j=a[i].l;j<=min(a[i].r,t);j++) 71 { 72 now1[c[j]]=now2[c[j]]=0; 73 } 74 ans[a[i].yuan]=tmp; 75 } 76 for(int i=1;i<=m;i++)printf("%d\n",ans[i]); 77 return 0; 78 }