还教室

【问题描述】

还记得NOIP 2012提高组Day2中的借教室吗?时光飞逝,光阴荏苒,两年
过去了,曾经借教室的同学们纷纷归还自己当初租借的教室。请你来解决类似于
借教室的另一个问题。
在接受借教室请求的n天中,第i天剩余的教室为ai个。作为大学借教室服
务的负责人,你需要完成如下三种操作共m次:
l天到第r天,每天被归还d个教室。
询问第l天到第r天教室个数的平均数。
询问第l天到第r天教室个数的方差。

【输入格式】

第一行包括两个正整数nm,其中n为借教室的天数,m 为操作次数。
接下来一行,共包含n个整数,第i个整数表示第i天剩余教室数目为ai个。
接下来m行,每行的第一个整数为操作编号(只能为123),接下来
包含两个正整数lr,若操作编号为1,则接下来再包含一个正整数d

【输出格式】

对于每个操作2和操作3,输出一个既约分数(分子与分母互质)表示询问
的答案(详见样例)。若答案为0,请输出“0/1”(不含引号)。

【样例输入】

5 4
1 2 3 4 5
1 1 2 3
2 2 4
3 2 4
3 1 5

【样例输出】

4/1
2/3
14/25

【数据范围】

对于全部测试数据满足:1 ≤ l ≤ r ≤ n,0 ≤ ai ≤ 10,1 ≤ d ≤ 3,操作 1 的数量
不超过 10%。注意:ai和 d 的范围很小及操作 1 数量很少的原因是为了保证答案
的分子不会很大,以防止答案的分子溢出 64 位整数的范围,这与题目做法无关。

【题解】

一看这种描述如此套路的题目就知道是数据结构题。
相当于维护区间加法,区间平均值,区间方差,这个可以用线段树维护。
平均值可以由区间和除以区间长度维护
区间方差,即∑(x ̅-xi)2**,可以转化为**(∑(x2) *len-(∑x)2)/(len2) 其中len是区间的长度
所以,只需要维护∑(x^2)和∑(x),也就是区间和以及区间平方和,就可以了。
剩下的就是线段树的事情了。
(调了2个半小时,还写了对拍,最后发现有一个地方忘long long了......)

【代码】

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#include<set>
using namespace std;
#define f(i,n) for(int i=1;i<=(n);i++)
#define ll long long
#define INF 1<<30
#define N 100010
int read()
{
    int x=0,f=1;char c=getchar();
    while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    while( isdigit(c)){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int a[N];
ll maxn[3*N],sum[3*N],minn[3*N],sumf[3*N],tag[3*N];
int n,q;
int z,ql,qr;
ll addi;
void pushup(int o,int l,int r)
{
    int lo=2*o,ro=2*o+1,m=(l+r)>>1;
    sum[o]=sum[lo]+sum[ro];
    maxn[o]=max(maxn[lo],maxn[ro]);
    minn[o]=min(minn[lo],minn[ro]);
    sumf[o]=sumf[lo]+sumf[ro];
}
void dingyi(int o,int l,int r)
{
    if(l==r)
    {
        sum[o]=maxn[o]=minn[o]=a[l];
        sumf[o]=a[l]*a[l];
        return;
    }
    int lo=2*o,ro=2*o+1,m=(l+r)>>1;
    dingyi(lo,l,m);
    dingyi(ro,m+1,r);
    pushup(o,l,r);
}
void pushdown(int o,int l,int r)
{
    if(l==r)return;
    int lo=2*o,ro=2*o+1,m=(l+r)>>1;
    if(tag[o])
    {
        tag[lo]+=tag[o];
        tag[ro]+=tag[o];
        sumf[lo]+=(ll)(m-l+1)*tag[o]*tag[o]+(ll)2*tag[o]*sum[lo];
        sumf[ro]+=(ll)(r-m)*tag[o]*tag[o]+(ll)2*tag[o]*sum[ro];
        sum[lo]+=(ll)(m-l+1)*tag[o];
        sum[ro]+=(ll)(r-m)*tag[o];
        maxn[lo]+=tag[o];
        maxn[ro]+=tag[o];
        minn[lo]+=tag[o];
        minn[ro]+=tag[o];
    }
    tag[o]=0;
}
void add(int o,int l,int r)
{
    if(l>=ql&&r<=qr)
    {
        sumf[o]+=(ll)(r-l+1)*addi*addi+2ll*addi*sum[o];
        sum[o]+=(ll)(r-l+1)*addi;
        maxn[o]+=addi;
        minn[o]+=addi;
        tag[o]+=addi;
        return;
    }
    pushdown(o,l,r);
    int lo=2*o,ro=2*o+1,m=(l+r)>>1;
    if(ql<=m)add(lo,l,m);
    if(qr>m)add(ro,m+1,r);
    pushup(o,l,r);
}
ll qsum=0,qsumf=0;
void query(int o,int l,int r)
{
    if(l>=ql&&r<=qr)
    {
        qsum+=sum[o];
        qsumf+=sumf[o];
        return;
    }
    int lo=2*o,ro=2*o+1,m=(l+r)>>1;
    pushdown(o,l,r);
    if(ql<=m)query(lo,l,m);
    if(qr>m)query(ro,m+1,r);
    pushup(o,l,r);
}
ll xj(ll a,ll b)
{
    if(b==0)return a;
    return xj(b,a%b);
}
void qj(ll a,ll b)
{    
    ll s=xj(a,b);
    printf("%lld/%lld\n",a/s,b/s);
}
int main()
{
    n=read();
    q=read();
    f(i,n)a[i]=read();
    dingyi(1,1,n);
    f(i,q)
    {
        z=read();
        ql=read();
        qr=read();
        if(z==1)
        {
            scanf("%lld",&addi);
            if(addi==0)continue;
            add(1,1,n);
        }
        if(z==2)
        {
            qsum=0;
            qsumf=0;
            query(1,1,n);
            qj(qsum,qr-ql+1);
        }
        if(z==3)
        {
            qsum=0;
            qsumf=0;
            query(1,1,n);
            //cout<<"qsum "<<qsum<<" qsumf "<<qsumf<<endl;        
            qj(qsumf*(ll)(qr-ql+1)-qsum*qsum,(ll)(qr-ql+1)*(ll)(qr-ql+1));
        }
    }
}
posted @ 2017-11-09 18:06  qwerfcxs  阅读(165)  评论(0编辑  收藏  举报