【题解】Luogu P3564 [POI 2014] BAR-Salad Bar 二分+单调队列

在咕了

 Updated

基本算法1-2


把$p,j$看成$1,-1$ 前缀和维护区间

区间$[l,r]$合法当且仅当$sum[l]≤sum[i]≤sum[r]$

当存在$p>x$且$sum[x]>sum[p]$时$x$不合法

发现$x$满足单调性

单调队列维护然后在单调队列上二分

一个记录当前仍符合条件的右端点,一个记录已经被扫过的左端点,每当有元素从第一个栈里弹出时,就在第二个栈里二分找出符合两个条件的最远的左端点

code

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 namespace gengyf{
 4 #define ll long long
 5 const int maxn=1e6+10;
 6 const int mod=1e9;
 7 inline int read(){
 8     int f=1,x=0;char s=getchar();
 9     while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
10     while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
11     return f*x;
12 }
13 int n,a[maxn],sum[maxn],q1[maxn],q2[maxn];
14 int r1,r2,ans=-1;
15 int find(int x){
16     int tmp=-1;
17     int l=1,r=r2;
18     while(l<=r){
19         int mid=(l+r)>>1;
20         if(q2[mid]>=x){
21             r=mid-1;tmp=mid;
22         }
23         else l=mid+1;
24     }
25 //    cout<<tmp<<" ";
26     return tmp==-1?-1:q2[tmp];
27 }
28 void Max(int &x,int y){
29     if(x==-1||x<y) x=y;
30 }
31 int main(){
32     n=read();
33     for(int i=1;i<=n;i++){
34         char c;cin>>c;
35         if(c=='p')a[i]=1;
36         else a[i]=-1;
37         sum[i]=sum[i-1]+a[i];
38     }
39     q1[++r1]=0;q2[++r2]=0;
40     for(int i=1;i<=n;i++){
41         while(r1&&sum[q1[r1]]<=sum[i])r1--;
42         int L=q1[r1]+1;
43         if(!r1)L=0;
44         q1[++r1]=i;
45         while(r2&&sum[q2[r2]]>sum[i])r2--;
46         int tmp=find(L);
47 //        cout<<tmp<<endl;
48         if(tmp==-1)tmp=i;
49         q2[++r2]=i;
50         
51         Max(ans,i-tmp);
52     }
53     printf("%d",ans);
54     return 0;
55 }
56 }
57 signed main(){
58   gengyf::main();
59   return 0;
60 }
View Code
原文地址:https://www.cnblogs.com/gengyf/p/11686815.html