zoukankan      html  css  js  c++  java
  • ZROI2018提高day4t3

    传送门

    分析

    我们假设如果一个点是0则它的值为-1,如果一个点是1则值为1,则一个区间的答案便是max(pre[i]+sur[i]),这里的pre[i]表示此区间i点和它之前的的前缀的最大值,sur[i]表示i点之后的后缀最大值。所以为了维护每个区间的答案我们可以用线段树进行维护。而对于一个由两个区间拼成的区间它的答案只有三种

    1. 由左区间所选的pre加上右区间的sur

    2. 由左区间的全部加上右区间的pre和sur

    3. 由左区间所选的pre和sur加上右区间的全部

    而这个区间的答案即为这三种的最大值。

    至于为什么是这三种情况请自行画图思考。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<cctype>
    #include<cmath>
    #include<cstdlib>
    #include<ctime>
    #include<queue>
    #include<vector>
    #include<set>
    #include<map>
    #include<stack>
    using namespace std;
    char s[200100];
    int a[200100];
    struct node {
          int pre,sur,ans,sum;
    };
    node d[800400];
    inline void up(int wh){
          d[wh].sum=d[wh<<1].sum+d[wh<<1|1].sum;
          d[wh].pre=max(d[wh<<1].pre,d[wh<<1].sum+d[wh<<1|1].pre);
          d[wh].sur=max(d[wh<<1|1].sur,d[wh<<1|1].sum+d[wh<<1].sur);
          d[wh].ans=max(d[wh<<1].pre+d[wh<<1|1].sur,
          max(d[wh<<1].sum+d[wh<<1|1].ans,d[wh<<1].ans+d[wh<<1|1].sum));
          return;
    }
    inline void build(int le,int ri,int wh){
          if(le==ri){
              d[wh].ans=d[wh].pre=d[wh].sur=max(a[le],0);
              d[wh].sum=a[le];
              return;
          }
          int mid=(le+ri)>>1;
          build(le,mid,wh<<1);
          build(mid+1,ri,wh<<1|1);
          up(wh);
          return;
    }
    inline node q(int le,int ri,int wh,int x,int y){
          if(le>=x&&ri<=y)return d[wh];
          int mid=(le+ri)>>1;
          node ans,a,b;
          int cnt=0;
          if(mid>=x)cnt++,ans=a=q(le,mid,wh<<1,x,y);
          if(mid<y)cnt++,ans=b=q(mid+1,ri,wh<<1|1,x,y);
          if(cnt==1)return ans;
          ans.sum=a.sum+b.sum;
          ans.pre=max(a.pre,a.sum+b.pre);
          ans.sur=max(b.sur,b.sum+a.sur);
          ans.ans=max(a.pre+b.sur,max(a.sum+b.ans,a.ans+b.sum));
          return ans;
    }
    int main(){
          int n,m,i,j,k,x,y;
          scanf("%d%d",&n,&m);
          scanf("%s",s);
          for(i=1;i<=n;i++)
            if(s[i-1]=='0')a[i]=-1;
              else a[i]=1;
          build(1,n,1);
          for(i=1;i<=m;i++){
              int x,y;
              scanf("%d%d",&x,&y);
              printf("%d
    ",q(1,n,1,x,y).ans);
          }
          return 0;
    }
  • 相关阅读:
    学习鸟哥linux私房菜--安装中文输入法fcitx
    学习鸟哥linux私房菜--安装centos5.6(u盘安装,中文乱码)
    CSS
    vue-cli脚手架搭建项目及Axios封装
    前端面试题套路
    移动端touch事件
    import和require的区别
    接口封装
    js 数组操作
    vue 小记
  • 原文地址:https://www.cnblogs.com/yzxverygood/p/9688569.html
Copyright © 2011-2022 走看看