[2020多校联考]选举

[BalkanOI2018]Election

Solution

推式子题,然后转换。考场上没有耐心,实际上应该能想出来。

Solution

答案是将 \(C\) 看成 \(1\)\(T\) 看成 \(-1\) 后,区间和减去区间最大子段和。

#include<stdio.h>
#define N 500007
#define rint register int
#define lid id<<1
#define rid id<<1|1

inline int read(){
    int x=0,flag=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')flag=0;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
    return flag? x:-x;
}

inline void out(int x){
    if(x<0) putchar('-'),x=-x;
    if(9<x) out(x/10);
    putchar(x%10^'0');
}

struct Node{
    int lm,rm,m,sum;
    void init(int x){lm=rm=m=sum=x;}
}t[N<<2];
int a[N];

inline int max(int x,int y){return x>y? x:y;}

inline void merge(Node &id,Node x,Node y){
    id.lm=max(x.lm,x.sum+y.lm);
    id.rm=max(y.rm,y.sum+x.rm);
    id.sum=x.sum+y.sum;
    id.m=max(x.rm+y.lm,max(id.lm,id.rm));
    id.m=max(id.m,max(x.m,y.m));
}

inline void build(int id,int lf,int rf){
    if(lf==rf) t[id].init(a[lf]);
    else{
        int mid=(lf+rf)>>1;
        build(lid,lf,mid);
        build(rid,mid+1,rf);
        merge(t[id],t[lid],t[rid]);
    }
}

int l,r;
inline Node query(int id,int lf,int rf){
    if(l<=lf&&rf<=r) return t[id];
    else{
        int mid=(lf+rf)>>1;
        if(r<=mid) return query(lid,lf,mid);
        if(l>mid) return query(rid,mid+1,rf);
        Node ret;ret.init(0);
        merge(ret,query(lid,lf,mid),query(rid,mid+1,rf));
        return ret;
    }
}

int n,m;
char s[N];
int main(){
//    freopen("elections.in","r",stdin);
//    freopen("elections.out","w",stdout);
    n=read();
    scanf("%s",s+1);
    for(rint i=1;i<=n;i++)
        a[i]=(s[i]=='C'? 1:-1);
    build(1,1,n);
    for(rint i=1;i<=n;i++)
        a[i]+=a[i-1];
    m=read();
    for(rint i=1;i<=m;i++){
        l=read(),r=read();
        Node ans=query(1,1,n);
        out(max(0,ans.m)-(a[r]-a[l-1]));
        putchar('\n');
    }
}
posted @ 2020-12-01 08:58  Kreap  阅读(82)  评论(0编辑  收藏  举报