重探线段树
方差
题意
\(1e5\) 范围处理区间加,区间平均数,区间方差。
做时思路
明显区间方差是这道题目的关键,其他两个与模板并无不同。
这里我们思考一下如何处理区间方差。
方差的计算公式向下推就完事儿了。
令其中有 \(k=r-l+1\) 个元素。
\(s^2=\frac{\sum\limits ^r_{i=l} (\bar{x}-x_i)^2}{k}\)
\(\ \quad =\frac{\sum\limits ^r_{i=l} (\bar{x}^2-2\bar{x} x_i +x_i^2)}{k}\)
\(\ \quad =\frac{1}{k}\sum\limits ^r_{i=l} x_i^2 - \bar{x}^2\)
平均值很好处理,就是处理平方和。处理平方和的关键柿子:
\((k_1+x)^2+(k_2+x)^2+...+(k_n+x)^2=k_1^2+k_2^2+k_3^2+...+k_n^2+2x\sum \limits ^n_{i=1} k_i + n x^2\)
然后注意一下平方和和普通和的处理顺序就 ok 力。
代码
#include <bits/stdc++.h>
#define debug puts("I love Newhanser forever!!!!!");
#define pb push_back
using namespace std;
const int MAXN=100086;
int n,m;
double a[MAXN];
struct Segment_Tree{
double sum[MAXN<<2],psum[MAXN<<2],tag[MAXN<<2];
int lc[MAXN<<2],rc[MAXN<<2];
int lson(int u){return u<<1;}
int rson(int u){return u<<1|1;}
bool in(int l,int r,int ll,int rr){return(l<=ll&&r>=rr);}
bool out(int l,int r,int ll,int rr){return l>rr||ll>r;}
void pushup(int u){sum[u]=sum[lson(u)]+sum[rson(u)];psum[u]=psum[lson(u)]+psum[rson(u)];}
void pushdown(int u){
if(tag[u]){
psum[lson(u)]=psum[lson(u)]+2.0*tag[u]*sum[lson(u)]+(rc[lson(u)]-lc[lson(u)]+1)*tag[u]*tag[u];
psum[rson(u)]=psum[rson(u)]+2.0*tag[u]*sum[rson(u)]+(rc[rson(u)]-lc[rson(u)]+1)*tag[u]*tag[u];
sum[lson(u)]+=(rc[lson(u)]-lc[lson(u)]+1)*tag[u];
sum[rson(u)]+=(rc[rson(u)]-lc[rson(u)]+1)*tag[u];
tag[lson(u)]+=tag[u];
tag[rson(u)]+=tag[u];
tag[u]=0;
}
}
void build(int u,int l,int r){
lc[u]=l;rc[u]=r;
if(l==r){sum[u]=a[l];psum[u]=a[l]*a[l];return;}
int mid=(l+r)>>1;
build(lson(u),l,mid);build(rson(u),mid+1,r);
pushup(u);
}
void update(int u,int l,int r,double va){
if(in(l,r,lc[u],rc[u])){
psum[u]+=2.0*va*sum[u]+(rc[u]-lc[u]+1)*va*va;
sum[u]+=(rc[u]-lc[u]+1)*va;
tag[u]+=va;
return;
}
if(out(l,r,lc[u],rc[u])) return;
pushdown(u);
update(lson(u),l,r,va);update(rson(u),l,r,va);
pushup(u);
}
double query_sum(int u,int l,int r){
if(out(l,r,lc[u],rc[u])) return 0;
if(in(l,r,lc[u],rc[u])) return sum[u];
pushdown(u);
return query_sum(lson(u),l,r)+query_sum(rson(u),l,r);
}
double query_psum(int u,int l,int r){
if(out(l,r,lc[u],rc[u])) return 0;
if(in(l,r,lc[u],rc[u])) return psum[u];
pushdown(u);
return query_psum(lson(u),l,r)+query_psum(rson(u),l,r);
}
}seg;
int main(){
cin>>n>>m;
for(int i=1;i<=n;++i) cin>>a[i];
seg.build(1,1,n);
while(m--){
int opt,x,y;
cin>>opt>>x>>y;
if(opt==1){
double k;
cin>>k;
seg.update(1,x,y,k);
}else{
if(opt==2){
cout<<fixed<<setprecision(4)<<(double)seg.query_sum(1,x,y)/(double)(y-x+1.0)<<endl;
}else{
//cout<<seg.query_psum(1,x,y)<<endl;
//cout<<fixed<<setprecision(4)<<(double)seg.query_psum(1,x,y)/n-((double)seg.query_sum(1,x,y)/(y*1.0-x+1.0))*((double)seg.query_sum(1,x,y)/(y*1.0-x+1.0))<<endl;
double ans=seg.query_psum(1,x,y)/(y-x+1);
double ans1=seg.query_sum(1,x,y)/(y-x+1);
cout<<fixed<<setprecision(4)<<ans-ans1*ans1<<endl;
}
}
}
return 0;
}
//Welcome back,Chtholly.
P2572 序列操作
题意
\(1e5\) 范围,所有元素为 \(0\) 或 \(1\) 。支持区修,区间异或 \(1\) ,区间查询 \(1\) 个数,区间查询最大连续 \(1\) 个数。
做时思路
调了下午半天 /yun 。其实是很多道题的糅合罢了。
区修普普通通不用多说。
区间异或 \(1\) 就是区间取反,既然是取反,那么即使只需要查询处理 \(1\) 的个数等等,其实还要维护 \(0\) 代码难度 \(\times 2\) 。
两个修改操作合在一起要注意区修的时候去掉区间异或的懒标记,因为区修的有限级高一点,然后如果一个元素已经有了区间修的标记,现在又要区间异或,那么就是区间修标记取反就行了。
区间查询 \(1\) 的个数普普通通不用多说。
区间查询最大连续 \(1\) 的个数。
小白逛公园,连续 \(1\) 的个数要么是左边的最大值要么是右边的最大值要么是左边靠中间的最大值加上右边靠中间的最大值合并起来。
注意一下代码的诸多细节即可。
代码
#include <bits/stdc++.h>
#define debug puts("I love Newhanser forever!!!!!");
#define pb push_back
using namespace std;
template <typename T>inline void read(T& t){
t=0; register char ch=getchar(); register int fflag=1;
while(!('0'<=ch&&ch<='9')){if(ch=='-') fflag=-1;ch=getchar();}
while(('0'<=ch&&ch<='9')){t=t*10+ch-'0'; ch=getchar();} t*=fflag;
}
template <typename T,typename... Args> inline void read(T& t, Args&... args){read(t);read(args...);}
const int MAXN=100086,inf=0x3f3f3f3f;
int a[MAXN];
struct Info{
int val,lval,rval,G;
};
struct Segment_Tree{
int val[MAXN<<2],lc[MAXN<<2],rc[MAXN<<2],lval[MAXN<<2],rval[MAXN<<2],sum[MAXN<<2],Val[MAXN<<2],tag[MAXN<<2],Lval[MAXN<<2],Sum[MAXN<<2],Rval[MAXN<<2],flag[MAXN<<2];
int lson(int u){return u<<1;}
int rson(int u){return u<<1|1;}
int L(int u){return rc[u]-lc[u]+1;}
inline bool in(int l,int r,int ll,int rr){return (l<=ll)&&(r>=rr);}
inline bool out(int l,int r,int ll,int rr){return (l>rr)||(ll>r);}
void pushup(int u){
sum[u]=sum[lson(u)]+sum[rson(u)];
val[u]=max(val[lson(u)],max(val[rson(u)],lval[rson(u)]+rval[lson(u)]));
lval[u]=(lval[lson(u)]==L(lson(u)))?sum[lson(u)]+lval[rson(u)]:lval[lson(u)];
rval[u]=(rval[rson(u)]==L(rson(u)))?sum[rson(u)]+rval[lson(u)]:rval[rson(u)];
Sum[u]=Sum[lson(u)]+Sum[rson(u)];
Val[u]=max(Val[lson(u)],max(Val[rson(u)],Lval[rson(u)]+Rval[lson(u)]));
Lval[u]=(Lval[lson(u)]==L(lson(u)))?Sum[lson(u)]+Lval[rson(u)]:Lval[lson(u)];
Rval[u]=(Rval[rson(u)]==L(rson(u)))?Sum[rson(u)]+Rval[lson(u)]:Rval[rson(u)];
}
void pushdown(int u){
if(tag[u]!=-1){
flag[u]=0;
tag[lson(u)]=tag[rson(u)]=tag[u];
lval[lson(u)]=rval[lson(u)]=val[lson(u)]=sum[lson(u)]=L(lson(u))*tag[u];
lval[rson(u)]=rval[rson(u)]=val[rson(u)]=sum[rson(u)]=L(rson(u))*tag[u];
Lval[lson(u)]=Rval[lson(u)]=Val[lson(u)]=Sum[lson(u)]=L(lson(u))*(!tag[u]);
Lval[rson(u)]=Rval[rson(u)]=Val[rson(u)]=Sum[rson(u)]=L(rson(u))*(!tag[u]);
tag[u]=-1;
}
if(flag[u]){
if(tag[lson(u)]!=-1) tag[lson(u)]^=1;
else flag[lson(u)]^=1;
if(tag[rson(u)]!=-1) tag[rson(u)]^=1;
else flag[rson(u)]^=1;
swap(sum[lson(u)],Sum[lson(u)]);
swap(sum[rson(u)],Sum[rson(u)]);
swap(val[lson(u)],Val[lson(u)]);
swap(val[rson(u)],Val[rson(u)]);
swap(lval[lson(u)],Lval[lson(u)]);
swap(lval[rson(u)],Lval[rson(u)]);
swap(rval[lson(u)],Rval[lson(u)]);
swap(rval[rson(u)],Rval[rson(u)]);
flag[u]=0;
}
}
void build(int u,int l,int r){
lc[u]=l;rc[u]=r;tag[u]=-1;flag[u]=0;
if(l==r){lval[u]=rval[u]=val[u]=sum[u]=a[l];Lval[u]=Rval[u]=Val[u]=Sum[u]=!a[l];return;}
int mid=l+r>>1;
build(lson(u),l,mid);build(rson(u),mid+1,r);
pushup(u);
}
void Update(int u,int l,int r,int va){
pushdown(u);
if(out(l,r,lc[u],rc[u])) return;
if(in(l,r,lc[u],rc[u])){flag[u]=0;lval[u]=rval[u]=sum[u]=val[u]=L(u)*va;Lval[u]=Rval[u]=Val[u]=Sum[u]=L(u)*(!va);tag[u]=va;return;}
Update(lson(u),l,r,va); Update(rson(u),l,r,va);
pushup(u);
}
void update(int u,int l,int r){
pushdown(u);
if(out(l,r,lc[u],rc[u])) return;
if(in(l,r,lc[u],rc[u])){swap(sum[u],Sum[u]); swap(val[u],Val[u]); swap(lval[u],Lval[u]); swap(rval[u],Rval[u]); flag[u]^=1;return;}
update(lson(u),l,r); update(rson(u),l,r);
pushup(u);
}
int query_sum(int u,int l,int r){
if(out(l,r,lc[u],rc[u])) return 0;
if(in(l,r,lc[u],rc[u])) return sum[u];
pushdown(u);
//cout<<u<<' '<<lc[u]<<'-'<<rc[u]<<' '<<flag[u]<<'\t'<<"1:::"<<sum[u]<<' '<<val[u]<<' '<<lval[u]<<' '<<rval[u]<<"\t 0:::"<<Sum[u]<<' '<<Val[u]<<' '<<Lval[u]<<' '<<Rval[u]<<endl;
return query_sum(lson(u),l,r)+query_sum(rson(u),l,r);
}
Info query_max(int u,int l,int r){
if(out(l,r,lc[u],rc[u])) return (Info){0,0,0,0};
if(in(l,r,lc[u],rc[u])) return (Info){val[u],lval[u],rval[u],rc[u]-lc[u]+1};
pushdown(u);
Info le=query_max(lson(u),l,r),ri=query_max(rson(u),l,r),tmp;
tmp.val=max(le.val,max(ri.val,le.rval+ri.lval));
tmp.G=le.G+ri.G;
//cout<<u<<' '<<lc[u]<<' '<<rc[u]<<' '<<ri.lval<<endl;
tmp.lval=(le.lval==le.G)?le.lval+ri.lval:le.lval;
tmp.rval=(ri.rval==ri.G)?ri.rval+le.rval:ri.rval;
return tmp;
}
void Debug(int u){
if(lc[u]==rc[u]) return;
Debug(lson(u)); Debug(rson(u));
}
}seg;
int n,Q;
int main(){
read(n,Q);
for(int i=1;i<=n;++i) read(a[i]);
seg.build(1,1,n);
while(Q--){
int opt,x,y;
read(opt,x,y);
++x;++y;
//seg.Debug(1);
if(opt==0||opt==1) seg.Update(1,x,y,opt);
else if(opt==2) seg.update(1,x,y);
else if(opt==3) cout<<seg.query_sum(1,x,y)<<endl;
else if(opt==4) cout<<seg.query_max(1,x,y).val<<endl;
}
return 0;
}
//Welcome back,Chtholly.
/*
10 2
0 0 0 1 1 0 1 0 1 1
1 0 2
3 0 5
*/