好题集 (3) - LG P2122 还教室

题目传送门

(多倍经验:P1471P10511P5142

题意:给定一数列,要求支持区间加法、区间方差、区间平均数。

首先做查询。平均数好做,考虑方差怎么搞。大力推柿子:

\[\begin{align*} s^2&=\frac{\sum\limits_{i=1}^n(x_i-\overline{x})^2}{n}\\ &=\frac{\sum\limits_{i=1}^n(x_i^2-2x_i+\overline{x}^2)}{n}\\ &=\frac{(n\overline{x}^2)+(\sum\limits_{i=1}^nx_i^2)-2\overline{x}\cdot(\sum\limits_{i=1}^nx_i)}{n}\\ &=\frac{\overline{x}(n\overline{x}-2\cdot\sum\limits_{i=1}^nx_i)+(\sum\limits_{i=1}^nx_i^2)}{n}\\ &=\frac{(\sum\limits_{i=1}^nx_i^2)-\overline{x}\cdot(\sum\limits_{i=1}^nx_i)}{n}\\ &=\frac{(\sum\limits_{i=1}^nx_i^2)-\frac{(\sum\limits_{i=1}^nx_i)^2}{n}}{n}\\ &=\frac{n\cdot(\sum\limits_{i=1}^nx_i^2)-(\sum\limits_{i=1}^nx_i)^2}{n} \end{align*} \]

这样就容易维护了。接下来考虑区间加时怎么更新整块的平方和,依旧推柿子:

\[\begin{align*} \sum\limits_{i=1}^n(x_i+v)^2&=\sum\limits_{i=1}^n(x_i^2-2x_iv+v^2)\\ &=(\sum\limits_{i=1}^nx_i^2)+2v\cdot(\sum\limits_{i=1}^nx_i)+nv^2 \end{align*} \]

然后分个块就可以做了。代码:

#include<iostream>
#include<cmath>
#define ll long long
using namespace std;

const int N=1e5+5;
const int M=320;

int n,m;

ll a[N];

namespace OIfast{
	
	#define gc getchar()
	
	inline unsigned read(){
		unsigned n=0;char c=gc;
		while(!isdigit(c))c=gc;
		while(isdigit(c))n=(n<<3)+(n<<1)+(c^48),c=gc;
		return n;
	}
	
}using namespace OIfast;

namespace Math{
	
	inline ll gcd(ll a,ll b){
		return b?gcd(b,a%b):a;
	}
	
	inline ll pf(ll x){
		return x*x;
	}
	
}using namespace Math;

namespace FK{
	
	int k,tot;
	
	short loc[N];
	int L[M],R[M];
	ll s[M],ss[M],la[M];
	
	inline void pushdown(int i){
		for(int j=L[i];j<=R[i];++j)a[j]+=la[i];
		return la[i]=0,void();
	}
	
	inline void pushup(int i){
		s[i]=ss[i]=0;for(int j=L[i];j<=R[i];++j)s[i]+=a[j],ss[i]+=pf(a[j]);
		return ;
	}
	
	inline void init(){
		k=sqrt(n),tot=ceil((1.0*n)/(1.0*k));
		for(int i=1;i<=tot;++i){
			L[i]=(i-1)*k+1,R[i]=min(n,L[i]+k-1);
			for(int j=L[i];j<=R[i];++j)loc[j]=i;
			pushup(i);
		}
		return ;
	}
	
	inline void upd(int l,int r,ll v){
		if(loc[l]==loc[r]){
			pushdown(loc[l]);for(int i=l;i<=r;++i)a[i]+=v;pushup(loc[l]);
		}else{
			pushdown(loc[l]);for(int i=l;i<=R[loc[l]];++i)a[i]+=v;pushup(loc[l]);
			pushdown(loc[r]);for(int i=L[loc[r]];i<=r;++i)a[i]+=v;pushup(loc[r]);
			for(int i=loc[l]+1;i<=loc[r]-1;++i)la[i]+=v,ss[i]+=2*v*s[i]+(R[i]-L[i]+1)*pf(v),s[i]+=(R[i]-L[i]+1)*v;
		}
		return ;
	}
	
	inline ll qry_s(int l,int r){
		ll res=0;
		if(loc[l]==loc[r]){
			pushdown(loc[l]);for(int i=l;i<=r;++i)res+=a[i];pushup(loc[l]);
		}else{
			pushdown(loc[l]);for(int i=l;i<=R[loc[l]];++i)res+=a[i];pushup(loc[l]);
			pushdown(loc[r]);for(int i=L[loc[r]];i<=r;++i)res+=a[i];pushup(loc[r]);
			for(int i=loc[l]+1;i<=loc[r]-1;++i)res+=s[i];
		}
		return res;
	}
	
	inline ll qry_ss(int l,int r){
		ll res=0;
		if(loc[l]==loc[r]){
			pushdown(loc[l]);for(int i=l;i<=r;++i)res+=pf(a[i]);pushup(loc[l]);
		}else{
			pushdown(loc[l]);for(int i=l;i<=R[loc[l]];++i)res+=pf(a[i]);pushup(loc[l]);
			pushdown(loc[r]);for(int i=L[loc[r]];i<=r;++i)res+=pf(a[i]);pushup(loc[r]);
			for(int i=loc[l]+1;i<=loc[r]-1;++i)res+=ss[i];
		}
		return res;
	}
	
	#define pii pair<ll,ll>
	#define mp make_pair
	#define fir first
	#define sec second
	
	inline pii dx(int l,int r){
		ll a=qry_s(l,r),b=r-l+1;
		if(!a)return mp(0,1);
		ll g=gcd(a,b);
		return mp(a/g,b/g);
	}
	
	inline pii fc(int l,int r){
		ll a=(r-l+1)*qry_ss(l,r)-pf(qry_s(l,r)),b=pf(r-l+1);
		if(!a)return mp(0,1);
		ll g=gcd(a,b);
		return mp(a/g,b/g);
	}
	
}using namespace FK;

inline void work(){
	int op=read(),l=read(),r=read();
	if(1==2)puts("wow");
	else if(op==1){ll d=read();upd(l,r,d);}
	else if(op==2){pii tmp=dx(l,r);printf("%lld/%lld\n",tmp.fir,tmp.sec);}
	else if(op==3){pii tmp=fc(l,r);printf("%lld/%lld\n",tmp.fir,tmp.sec);}
	return ;
}

signed main(){
	n=read(),m=read();for(int i=1;i<=n;++i)a[i]=read();
	init();while(m--)work();
	return 0;
}

提交记录

posted @ 2025-11-14 19:37  DX3906_ourstar  阅读(3)  评论(0)    收藏  举报