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\n",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\n",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\n",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\n",sum[1]);
    }
    return 0;
}

 


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

你考虑。。

维护每个区间的答案

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

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

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

log^2了

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

不是斜率

讨论最大值的来源

是这样的

对于x

左边最大值是y

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

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

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

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

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

每次都只会递归一侧

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

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

 

可以参考:上帝之手

posted @ 2017-03-28 21:03  神犇(shenben)  阅读(275)  评论(0编辑  收藏  举报