zoukankan      html  css  js  c++  java
  • Codevs 5914 [SXOI2016]最大值

    70分算法+30分打表

    #include<ctime>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #define lc k<<1
    #define rc k<<1|1
    #define EF if(ch==EOF) return x;
    using namespace std;
    const int N=1e5+5;
    const int inf=2e9;
    typedef long long ll;
    int n,Q,ans,a[N],mx[N];
    ll sum[N<<2];bool tag[N<<2];
    inline int read(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;EF;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    void build(int k,int l,int r){
        if(l==r){
            sum[k]=mx[l];
            return ;
        }
        int mid=l+r>>1;
        build(lc,l,mid);
        build(rc,mid+1,r);
        sum[k]=sum[lc]+sum[rc];
    }
    void pushdown(int k,int l,int r){
        if(!tag[k]||l==r) return ;
        int mid=l+r>>1;
        sum[lc]=sum[k]/(r-l+1)*(mid-l+1);
        sum[rc]=sum[k]/(r-l+1)*(r-mid);
        tag[lc]=tag[rc]=1;tag[k]=0;
    }
    void change(int k,int l,int r,int x,int y,int v){
        if(l==x&&r==y){
            sum[k]=1LL*(r-l+1)*v;
            tag[k]=1;
            return ;
        }
        pushdown(k,l,r);
        int mid=l+r>>1;
        if(y<=mid) change(lc,l,mid,x,y,v);
        else if(x>mid) change(rc,mid+1,r,x,y,v);
        else change(lc,l,mid,x,mid,v),change(rc,mid+1,r,mid+1,y,v);
        sum[k]=sum[lc]+sum[rc];
    }
    ll query(int k,int l,int r,int p){
        if(l==r) return sum[k];
        pushdown(k,l,r);
        int mid=l+r>>1;
        if(p<=mid) return query(lc,l,mid,p);
        else return query(rc,mid+1,r,p);
    //    sum[k]=sum[lc]+sum[rc];
    }
    void ord(){
        int Max=-inf;ans=0;
        for(int j=1;j<=n;j++){
            Max=max(Max,a[j]);
            ans+=Max;
        }
        printf("%d
    ",ans);
        for(int i=1,x,y;i<=Q;i++){
            x=read();y=read();
            a[x]+=y;
            int Max=-inf;ans=0;
            for(int j=1;j<=n;j++){
                Max=max(Max,a[j]);
                ans+=Max;
            }
            printf("%d
    ",ans);
        }
    }
    int main(){
        n=read();
        for(int i=1;i<=n;i++) a[i]=read();Q=read();
        if(n<=2000){
            ord();
            return 0;
        }
        mx[0]=-inf;
        for(int i=1;i<=n;i++) mx[i]=max(mx[i-1],a[i]);
        build(1,1,n);printf("%I64d
    ",sum[1]);
        for(int i=1,x,y;i<=Q;i++){
            x=read();y=read();
            a[x]+=y;
            int l=x,r=n,pos=0;
            while(l<=r){
                int mid=l+r>>1;
                if(query(1,1,n,mid)<a[x]) l=mid+1,pos=mid;
                else r=mid-1;
            }
            if(pos) change(1,1,n,x,pos,a[x]);
            printf("%I64d
    ",sum[1]);
        }
        return 0;
    }


    如果你会线段树log^2求单调栈的话..此题可做

    你考虑。。

    维护每个区间的答案

    以及一个看似暴力的询问函数(x,y)

    表示从x节点出发 左边max是y的答案

    然后你会发现每次只需要递归到一侧

    log^2了

    对啊……好像是维护斜率啥的吧……

    不是斜率

    讨论最大值的来源

    是这样的

    对于x

    左边最大值是y

    如果你发现x左儿子最大值<=y

    那么显然没有递归左儿子的必要

    否则递归完左儿子后,右儿子的答案与y无关

    因为变成了x左儿子的最大值

    这个通过线段树之前维护的信息就可以知道

    每次都只会递归一侧

    不管是查询还是信息合并都用这个logn的函数就好了

    线段树维护的是什么呀?
    区间最大值
    以及区间的答案

    可以参考:上帝之手

  • 相关阅读:
    BZOJ2648: SJY摆棋子
    BZOJ1925: [Sdoi2010]地精部落
    BZOJ1941: [Sdoi2010]Hide and Seek
    BZOJ2434: [Noi2011]阿狸的打字机
    BZOJ3295: [Cqoi2011]动态逆序对
    BZOJ1406: [AHOI2007]密码箱
    BZOJ1115: [POI2009]石子游戏Kam
    BZOJ1531: [POI2005]Bank notes
    BZOJ2730: [HNOI2012]矿场搭建
    计算几何《简单》入土芝士
  • 原文地址:https://www.cnblogs.com/shenben/p/6636863.html
Copyright © 2011-2022 走看看