「BalkanOI 2018 Day1」Election
其实如果真的要删的话,前缀最小值是负值的前缀最小值位置之前产生负贡献的位置都是要删的,后缀同理
我们令 \(pre_i\) 表示前缀, \(suf_i\) 表示后缀
仅考虑前缀的话贡献就是 \(-min\{pre_i\}\)
此时后缀的值会改变,即:\(suf_i'=suf_i-min\{pre_i\}+min_{j<i}\{pre_j\}\)
那么总答案的贡献就为:
\[-min\{pre_i\}-min\{suf_i'\}
\]
\[-min\{suf_i+min_{j<i}\{pre_j\}\}
\]
一个神奇的转化,我们把答案的式子加上总和
于是我们就要求最大字段和了
Code
#include<bits/stdc++.h>
#define re register
#define int long long
#define lls long long
#define fr first
#define sc second
#define pb push_back
using namespace std;
const int mol=1e9+7;
const int maxn=1e7+10;
const int INF=1e9+10;
inline int qpow(int a,int b) { int ans=1; while(b) { if(b&1) (ans*=a)%=mol; (a*=a)%=mol; b>>=1; } return ans; }
inline int read() {
int w=1,s=0; char ch=getchar();
while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
while(ch>='0'&&ch<='9') { s=s*10+ch-'0'; ch=getchar(); }
return s*w;
}
#define lid (id<<1)
#define rid (id<<1|1)
int n,m,w[maxn],sum[maxn]; char c[maxn];
namespace STG {
struct TREE { int id,sum,ls,rs,ks; } tre[maxn<<2];
inline void merge(TREE & a,TREE b,TREE c) {
a.ls=max(b.ls,b.sum+c.ls);
a.rs=max(c.rs,c.sum+b.rs);
a.ks=max(max(b.ks,c.ks),max(max(a.ls,a.rs),b.rs+c.ls));
a.sum=b.sum+c.sum;
}
inline void build(int id,int l,int r) {
if(l==r) { tre[id].sum=w[l]; if(w[l]>0) tre[id].ls=tre[id].rs=tre[id].ks=1; return ; }
int mid=(l+r)>>1;
build(lid,l,mid); build(rid,mid+1,r);
merge(tre[id],tre[lid],tre[rid]);
}
inline TREE quy(int id,int l,int r,int ll,int rr) {
if(ll<=l&&r<=rr) return tre[id];
int mid=(l+r)>>1; TREE as=(TREE){ 0,0,0,0,0 },as1=(TREE){ 0,0,0,0,0 },as2=(TREE){ 0,0,0,0,0 };
if(ll<=mid) as1=quy(lid,l,mid,ll,rr);
if(rr>mid) as2=quy(rid,mid+1,r,ll,rr);
merge(as,as1,as2);
return as;
}
}
signed main(void) {
freopen("d.in","r",stdin); freopen("d.out","w",stdout);
n=read();
scanf("%s",c+1);
for(re int i=1;i<=n;i++) { if(c[i]=='C') w[i]=1; else w[i]=-1; sum[i]=sum[i-1]+w[i]; }
STG::build(1,1,n);
m=read();
for(re int i=1,l,r;i<=m;i++) {
l=read(); r=read();
printf("%lld\n",max(0ll,STG::quy(1,1,n,l,r).ks-(sum[r]-sum[l-1])));
}
}