• 【NOIp模拟赛】还教室


    【引子】
    还记得 NOIP 2012 提高组 Day2 中的借教室吗?时光飞逝,光阴荏苒,两年过去了,曾经借教室的同学们纷纷归还自己当初租借的教室。请你来解决类似于借教室的另一个问题。
    【问题描述】
    在接受借教室请求的 n 天中,第 i 天剩余的教室为 ai 个。作为大学借教室服务的负责人,你需要完成如下三种操作共 m 次:
    ① 第 l 天到第 r 天,每天被归还 d 个教室。
    ② 询问第 l 天到第 r 天教室个数的平均数。
    ③ 询问第 l 天到第 r 天教室个数的方差。
    【输入格式】
    第一行包括两个正整数 n 和 m,其中 n 为借教室的天数,m 为操作次数。
    接下来一行,共包含 n 个整数,第 i 个整数表示第 i 天剩余教室数目为 ai 个。
    接下来 m 行,每行的第一个整数为操作编号(只能为 1 或 2 或 3) ,接下来包含两个正整数 l 和 r,若操作编号为 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

    【样例说明】

    【数学小贴士】

    【数据规模与约定】

    分析

    区间修改和区间查询,很明显这是一道线段树的题。关于平均数的求法,只要记录区间和就行了,麻烦一点的就是方差。

    为了方便举例子,例如求两个数x1,x2的方差,设t是t=(x1+x2)/2; 那么方差p=((x1-t)^2+(x2-t)^2)/2; 展开得到

    p=((x1^2+x2^2)-2(x1+x2)*t+2*t^2)/2; 可以发现只需要这个区间的平方和和区间和就可以求出方差(平均数可以用区间和求得),之后用线段树维护就行了。

    还有一点是要注意要防止过程量溢出。

    代码

    代码虽然很长(线段树的代码貌似都不短),但是思路清晰地话代码的长的不是问题。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn=100000+5;
    typedef long long ll;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    int n,m,len;
    int a[maxn];
    struct node
    {
        int l,r,lc,rc;
        ll c,mul,add;
    }tr[maxn<<1];
    void bt(int x,int y)
    {
        len++; int now=len;
        tr[now].l=x; tr[now].r=y;
        tr[now].lc=tr[now].rc=0;
        if(x==y) 
        { tr[now].c=a[x]; tr[now].mul=a[x]*a[x]; }
        else
        {
            int mid=(x+y)>>1;
            tr[now].lc=len+1; bt(x,mid);
            tr[now].rc=len+1; bt(mid+1,y);
            tr[now].c=tr[tr[now].lc].c+tr[tr[now].rc].c;
            tr[now].mul=tr[tr[now].lc].mul+tr[tr[now].rc].mul;
        }
    }
    inline void pushdown(int now)
    {
        if(tr[now].l==tr[now].r||!tr[now].add) return;
        int lc=tr[now].lc,rc=tr[now].rc;
        tr[lc].mul=tr[lc].mul+2*tr[lc].c*tr[now].add+(tr[lc].r-tr[lc].l+1)*tr[now].add*tr[now].add;
        tr[rc].mul=tr[rc].mul+2*tr[rc].c*tr[now].add+(tr[rc].r-tr[rc].l+1)*tr[now].add*tr[now].add;
        tr[lc].c=tr[lc].c+(tr[lc].r-tr[lc].l+1)*tr[now].add;
        tr[rc].c=tr[rc].c+(tr[rc].r-tr[rc].l+1)*tr[now].add;
        tr[lc].add+=tr[now].add; tr[rc].add+=tr[now].add;
        tr[now].add=0;
    }
    void update(int now,int x,int y,int d)
    {
        if(tr[now].l==x&&tr[now].r==y)
        {
            tr[now].mul=tr[now].mul+2*tr[now].c*d+(tr[now].r-tr[now].l+1)*d*d;
            tr[now].c=tr[now].c+(y-x+1)*d;
            tr[now].add+=d;
        }else
        {
            pushdown(now);
            int lc=tr[now].lc,rc=tr[now].rc;
            int mid=(tr[now].l+tr[now].r)>>1;
            if(y<=mid) update(lc,x,y,d);
            else if(x>=mid+1) update(rc,x,y,d);
            else {  update(lc,x,mid,d); update(rc,mid+1,y,d); }
            tr[now].c=tr[lc].c+tr[rc].c;
            tr[now].mul=tr[lc].mul+tr[rc].mul;
        }
    }
    ll getsum(int now,int x,int y)
    {
        if(tr[now].l==x&&tr[now].r==y)
            return tr[now].c;
        else
        {
            pushdown(now);
            int lc=tr[now].lc,rc=tr[now].rc;
            int mid=(tr[now].l+tr[now].r)>>1;
            if(y<=mid) return getsum(lc,x,y);
            else if(x>=mid+1) return getsum(rc,x,y);
            else return getsum(lc,x,mid)+getsum(rc,mid+1,y);
        }
    }
    ll getmul(int now,int x,int y)
    {
        if(tr[now].l==x&&tr[now].r==y)
            return tr[now].mul;
        else
        {
            pushdown(now);
            int lc=tr[now].lc,rc=tr[now].rc;
            int mid=(tr[now].l+tr[now].r)>>1;
            if(y<=mid) return getmul(lc,x,y);
            else if(x>=mid+1) return getmul(rc,x,y);
            else return getmul(lc,x,mid)+getmul(rc,mid+1,y);
        }
    }
    ll gcd(ll a, ll b)
    {
        if(b==0) return a;
        return gcd(b,a%b);
    }
    int main()
    {
        freopen("classroom.in","r",stdin);
        freopen("classroom.out","w",stdout);
        n=read();m=read();
        for(int i=1;i<=n;i++) a[i]=read();
        bt(1,n);
        for(int i=1;i<=m;i++)
        {
            int p,x,y,d;
            p=read();
            if(p==1)
            {
                x=read(); y=read(); d=read();
                update(1,x,y,d);
            }else
            {
                x=read(); y=read();
                ll sum,num,fz,fm,t;
                sum=getsum(1,x,y); num=y-x+1;
                if(!sum){printf("%d/%d
    ",0,1); continue;}
                t=gcd(sum,num);
                if(p==2) printf("%lld/%lld
    ",sum/t,num/t);
                else if(p==3)
                {
                    ll mul=getmul(1,x,y);
                    fz=mul*num-sum*sum;
                    fm=num*num;
                    t=gcd(fz,fm);
                    printf("%lld/%lld
    ",fz/t,fm/t);
                }
            }
        }
        fclose(stdin); fclose(stdout);
        return 0;
    }
        
        
    欢迎转载,转载请注明出处!
  • 相关阅读:
    solr dataimport 数据导入源码分析(九)
    正确理解ThreadLocal
    solr dataimport 数据导入源码分析(六)
    solr dataimport 数据导入源码分析(七)
    solr dataimport 数据导入源码分析(八)
    solr dataimport 数据导入源码分析(一)
    solr dataimport 数据导入源码分析(五)
    OpenGL光照、键盘
    OpenGL着色
    OpenGL纹理映射
  • 原文地址:https://www.cnblogs.com/huihao/p/7454737.html
Copyright © 2020-2023  润新知