luogu P5142 区间方差 十分优美的线段树
又来了个维护方差的线段树。。。。
大致推导过程(字丑多包涵QAQ)
注意取模时要加一些100000007防止出现负数。。
#include<cstdio> #include<iostream> #define ll long long #define R register long long #define ls (tr<<1) #define rs (tr<<1|1) using namespace std; const long long M=1000000007; int n,m; inline ll g() { R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix; do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix; } ll sum[400010],po[400010]; void build(int tr,int l,int r) { if(l==r) {sum[tr]=g(),po[tr]=sum[tr]*sum[tr]; return;} R md=(l+r)>>1; build(ls,l,md),build(rs,md+1,r); sum[tr]=sum[ls]+sum[rs],po[tr]=po[ls]+po[rs]; } void add(int tr,int l,int r,int pos,ll d) { if(l==r) {sum[tr]=d%M; po[tr]=d*d%M; return ;} R md=(l+r)>>1; if(pos>md) add(rs,md+1,r,pos,d); else if(pos<md+1) add(ls,l,md,pos,d); sum[tr]=(sum[ls]+sum[rs])%M,po[tr]=(po[ls]+po[rs])%M; } ll query(int tr,int l,int r,int LL,int RR) { if(l==LL&&r==RR) return sum[tr]; R md=(l+r)>>1; if(LL>md) return query(rs,md+1,r,LL,RR); else if(RR<md+1) return query(ls,l,md,LL,RR); else return (query(ls,l,md,LL,md)+query(rs,md+1,r,md+1,RR))%M; } ll _query(int tr,int l,int r,int LL,int RR) { if(l==LL&&r==RR) return po[tr]; R md=(l+r)>>1; if(LL>md) return _query(rs,md+1,r,LL,RR); else if(RR<md+1) return _query(ls,l,md,LL,RR); else return (_query(ls,l,md,LL,md)+_query(rs,md+1,r,md+1,RR))%M; } inline ll qpow(int a) { R ret=1,p=M-2; a%=M; for(;p;p>>=1,(a*=a)%=M) if(p&1) (ret*=a)%=M; return ret; } inline ll Inv(int x) { if(x==1) return 1; if(x<1) return 0; return (M-M/x)*Inv(M%x)%M; } signed main() { n=g(),m=g(); build(1,1,n); for(R i=1;i<=m;++i) { R k=g(),l=g(),r=g(); if(k&1) add(1,1,n,l,r); else { R inv=Inv(r-l+1),ave=query(1,1,n,l,r)*inv%M; printf("%lld\n",((_query(1,1,n,l,r)%M-(ave<<1)*query(1,1,n,l,r)%M+M)*inv%M+ave*ave%M+M)%M); } } }
也可树状数组,就不多说了(自己没写)(怕是树状数组更易写?)
2019.04.12