CodeForces 212D

线段树
对于每个数字,分别处理更新
区间修改+等差数列

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int N=1e6+100;
typedef __int64 LL;
LL add[N<<2],st[N<<2],cha[N<<2];
#define ll o<<1
#define rr o<<1|1
#define mid (l+r)/2

void down(int l,int r,int o){
    add[ll]+=add[o];
    add[rr]+=add[o];
    add[o]=0;

    st[ll]+=st[o];cha[ll]+=cha[o];
    st[rr]+=st[o]+(LL)(mid+1-l)*cha[o];cha[rr]+=cha[o];
    st[o]=0,cha[o]=0;
}

int L,R;LL V,V1;int op;
void update(int l,int r,int o){
    if(L<=l&&r<=R){
        if(op==0){
            add[o]+=V;
        }
        else {
            st[o]+=V+(LL)(l-L)*V1;
            cha[o]+=V1;
        }
        return ;
    }
    down(l,r,o);
    if(L<=mid)update(l,mid,ll);
    if(R>mid)update(mid+1,r,rr);
}
LL query(int l,int r,int o,int x){
    if(l==r){
        return add[o]+st[o];
    }
    down(l,r,o);
    if(x<=mid)return query(l,mid,ll,x);
    else return query(mid+1,r,rr,x);
}

int le[N],ri[N],aa[N];
int n;
void getlr(){
    for(int i=1;i<=n;i++){
        int j=i-1;
        while(aa[j]>=aa[i]){
            j=le[j];
        }
        le[i]=j;
    }

    for(int i=n;i>=1;i--){
        int j=i+1;
        while(aa[j]>aa[i]){
            j=ri[j];
        }
        ri[i]=j;
    }
}

void getup(){
    memset(add,0,sizeof(add));
    memset(st,0,sizeof(st));
    memset(cha,0,sizeof(cha));
    for(int i=1;i<=n;i++){
        int x=i-(le[i]+1),y=(ri[i]-1)-i;
        if(x>y)swap(x,y);
        L=1,R=x+1,V=aa[i],V1=aa[i],op=1;
        update(1,n,1);

        L=x+2,R=x+1+y-x,V=(LL)(x+1)*aa[i],op=0;
        if(L<=R)update(1,n,1);

        L=x+1+y-x+1,R=x+1+y,V=(LL)x*aa[i],V1=-aa[i],op=1;
        if(L<=R)update(1,n,1);
    }
}
void pri(int xx[N],int n){
    for(int i=1;i<=n;i++){
        printf("%d%c",xx[i],i==n?'\n':' ');
    }
}
int main(){
    #ifdef DouBi
    freopen("in.cpp","r",stdin);
    #endif // DouBi
    while(scanf("%d",&n)!=EOF){
        for(int i=1;i<=n;i++){
            scanf("%d",&aa[i]);
        }
        aa[0]=aa[n+1]=0;
        getlr();
        //pri(le,n);
        //pri(ri,n);
        getup();

        int m;scanf("%d",&m);
        for(int i=0;i<m;i++){
            int a;scanf("%d",&a);
            LL ans=query(1,n,1,a);
            printf("%.10lf\n",(double)ans/(n-a+1));
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值