计蒜客信息学赛前CSP-S2模拟赛2 T4 平均数

问题描述

有一个长度为 n* 的序列,求所有长度大于等于 m 的子区间的平均数的最大值。

还有 q 次单点加操作,每次操作后输出长度大于等于 m 的子区间的平均数的最大值。

输入格式

第一行三个正整数 \(n,M,q\),其中 \(M\geq\) 所有询问的 \(m\) 值。

第二行 \(n\) 个整数表示该序列。

下面 \(q\) 行每行三个正整数 \(x,c,m\),表示将位置 \(x\)\(c\) 之后,长度大于等于 m 的子区间的平均数的最大值。

输出格式

输出 \(q\) 行,第 \(i\) 行输出两个正整数 \(X,Y\),表示平均数的最大值为 \(X/Y\)。(\(X/Y\) 是最简分数)

数据范围

\(1\le n\le 125000,m\le \min(50,n),q\le 20000,a_i,c_i\le 10^9\)

解析

对于一个询问,最后选择的区间长度不会超过 \(2m\) 。因为超过 \(2m\) 的区间我们一定可以把它划分为两个区间,满足这两个区间有一个的平均数大于原区间。

因此,我们不妨维护 \(2M\) 个线段树,第 \(k\) 个线段树中维护序列第 \(i\) 位开始的长度为 \(k\) 的区间和。单点加操作就是线段树区间修改。对于每一个询问,我们只需要查询第 \(m\) 到第 \(2m-1\) 棵线段树的最小值,然后更新答案即可。

实际上我们不需要同时维护 \(2M\) 个线段树。我们可以把询问离线下来,然后枚举长度并依次维护第 \(1\) 到第 \(2M\) 棵线段树。每棵线段树都更新一下所有能够更新的询问。

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#define N 125002
using namespace std;
const double eps=1e-8;
struct query{
	int x,c,m;
}q[N];
struct SegmentTree{
	long long dat,add;
}t[N*4];
int n,m,p,i,l,a[N],ansy[N];
long long sum[N],ansx[N];
int read()
{
	char c=getchar();
	int w=0;
	while(c<'0'||c>'9') c=getchar();
	while(c<='9'&&c>='0'){
		w=w*10+c-'0';
		c=getchar();
	}
	return w;
}
void spread(int p)
{
	if(t[p].add){
		t[p*2].dat+=t[p].add;t[p*2+1].dat+=t[p].add;
		t[p*2].add+=t[p].add;t[p*2+1].add+=t[p].add;
		t[p].add=0;
	}
}
void build(int p,int l,int r,int x)
{
	t[p].dat=t[p].add=0;
	if(l==r){
		t[p].dat=sum[l+x-1]-sum[l-1];
		return;
	}
	int mid=(l+r)/2;
	build(p*2,l,mid,x);build(p*2+1,mid+1,r,x);
	t[p].dat=max(t[p*2].dat,t[p*2+1].dat);
}
void change(int p,int l,int r,int ql,int qr,int x)
{
	if(ql>qr) return;
	if(ql<=l&&r<=qr){
		t[p].dat+=x;t[p].add+=x;
		return;
	}
	int mid=(l+r)/2;
	spread(p);
	if(ql<=mid) change(p*2,l,mid,ql,qr,x);
	if(qr>mid) change(p*2+1,mid+1,r,ql,qr,x);
	t[p].dat=max(t[p*2].dat,t[p*2+1].dat);
}
int gcd(int a,int b)
{
	if(!b) return a;
	return gcd(b,a%b);
}
signed main()
{
	freopen("average.in","r",stdin);
	freopen("average.out","w",stdout);
	n=read();m=read();p=read();
	for(i=1;i<=n;i++) a[i]=read();
	for(i=1;i<=p;i++) q[i].x=read(),q[i].c=read(),q[i].m=read();
	for(i=1;i<=n;i++) sum[i]=sum[i-1]+a[i];
	for(l=1;l<=min(2*m-1,n);l++){
		build(1,1,n-l+1,l);
		for(i=1;i<=p;i++){
			int L=max(1,q[i].x-l+1),R=min(n-l+1,q[i].x);
			change(1,1,n-l+1,L,R,q[i].c);
			if(l>=q[i].m&&l<2*q[i].m){
 				if(ansy[i]==0||(long double)t[1].dat/l-(long double)ansx[i]/ansy[i]>eps) ansx[i]=t[1].dat,ansy[i]=l;
			}
		}
	}
	for(i=1;i<=p;i++){
		int d=gcd(ansx[i]%ansy[i],ansy[i]);
		printf("%lld %d\n",ansx[i]/d,ansy[i]/d);
	}
	return 0;
}
posted @ 2020-11-01 23:21  CJlzf  阅读(190)  评论(0编辑  收藏  举报