zoukankan      html  css  js  c++  java
  • HAOI2012 高速公路 线段树

    题目描述

    Y901高速公路是一条重要的交通纽带,政府部门建设初期的投入以及使用期间的养护费用都不低,因此政府在这条高速公路上设立了许多收费站。 Y901高速公路是一条由N-1段路以及N个收费站组成的东西向的链,我们按照由西向东的顺序将收费站依次编号为1~N,从收费站i行驶到i+1(或从i+1行驶到i)需要收取Vi的费用。高速路刚建成时所有的路段都是免费的。 政府部门根据实际情况,会不定期地对连续路段的收费标准进行调整,根据政策涨价或降价。 无聊的小A同学总喜欢研究一些稀奇古怪的问题,他开车在这条高速路上行驶时想到了这样一个问题:对于给定的l,r(l<r),在第l个到第r个收费站里等概率随机取出两个不同的收费站a和b,那么从a行驶到b将期望花费多少费用呢?

    输入格式

    第一行2个正整数N,M,表示有N个收费站,M次调整或询问 接下来M行,每行将出现以下两种形式中的一种 C l r v 表示将第l个收费站到第r个收费站之间的所有道路的通行费全部增加v Q l r 表示对于给定的l,r,要求回答小A的问题 所有C与Q操作中保证1<=l<r<=N

    输出格式

    对于每次询问操作回答一行,输出一个既约分数 若答案为整数a,输出a/1

    样例

    样例输入

    4 5
    C 1 4 2
    C 1 2 -1
    Q 1 2
    Q 2 4
    Q 1 4

    样例输出

    1/1
    8/3
    17/6

    数据范围与提示

    所有C操作中的v的绝对值不超过10000

    在任何时刻任意道路的费用均为不超过10000的非负整数

    所有测试点的详细情况如下表所示

    Test N M

    1 =10 =10

    2 =100 =100

    3 =1000 =1000

    4 =10000 =10000

    5 =50000 =50000

    6 =60000 =60000

    7 =70000 =70000

    8 =80000 =80000

    9 =90000 =90000

    10 =100000 =100000

      首先这个题一看就是一道数据结构题,废话,考虑一下这个题要求什么,一般用分数表示的概率期望都是假的,不要问我为什么。。这道题其实就是要找一个子区间的和,再除以选端点的方案数$C_{len}^{2}$,那么好像暴力只能用$O(n^3)$打,毕竟枚举子区间就要$n^2$的。

      我们现在要考虑暴力如何优化,这道题和HAOI的另一道题树上染色的思路很像,那个题中两点距离通过找边的贡献得到,进而把枚举两点变做加边贡献,那么这个题也从这个思路考虑,枚举每一段路的贡献,那么我们就的到了$O(n)$修改/查询的式子:

    $sum limits_{i=l}^{r} s[i]*(r-i+1)*(i-l+1)$

    这个使我们成功转化思路,这样的优化暴力能水过90分,已经非常优秀了。如果要A过,我们考虑用线段树去维护这个东西,我们首先的对这个式子变形,目的是得到可以区间合并的并且log查询的东西。我们先把括号都拆掉。

      $sum limits_{i=l}^{r} s[i]*i*(l+r)-s[i]*i^{2}-s[i]*(l-1)*(r+1)$

      然后把常数提出来,能一起维护的放在一起。

      $(l+r)*sum limits_{i=l}^{r} s[i]*i-sum limits_{i=l}^{r}s[i]*i^{2}-(l-1)(r+1)*sum limits_{i=l}^{r}s[i]$

      那么我们已经发现,此时我们对于一个区间,只需要维护它的$s[i]$,$s[i]*i^{2}$,$s[i]*i$就可以了。

      查询已经解决,那么如何修改呢,$s[i]$,$s[i]*i$都比较简单,一个是加$w*1$,一个是$s[i]*i+w*i$等差数列即可,最后是$s[i]*i^{2}+w*i^{2}$,这个平方就要用到自然数方幂和公式,借此机会习得拉格朗日插值。当然只要知道公式就可以了$n(n+1)(2n+1)/6$。

      友情提示,懒标记是用来叠加的,不是用来覆盖的。。。。

      

    #include<iostream>
    #include<cstdio>
    #define ll long long
    #define int long long
    using namespace std;
    const int N=1000020,M=100020;
    struct node
    {
        ll s,si,sii;
        node operator +(node b)
        {
            node c;c.s=c.si=c.sii=0;
            c.s=s+b.s;
            c.si=si+b.si;
            c.sii=sii+b.sii;
            return c;
        }
    };
    struct tree{int l,r;ll f;node s;}tr[4*N];
    int rd()
    {
        int s=0,w=1;
        char cc=getchar();
        while(cc<'0'||cc>'9') {if(cc=='-') w=-1;cc=getchar();}
        while(cc>='0'&&cc<='9') s=(s<<3)+(s<<1)+cc-'0',cc=getchar();
        return s*w;
    }
    void change(int k,int w)
    {
        int l=tr[k].l,r=tr[k].r;
        tr[k].s.s+=1ll*w*(r-l+1);
        tr[k].s.si+=1ll*w*((l+r)*(r-l+1)/2);
        tr[k].s.sii+=1ll*w*((r*(r+1)*(2*r+1)-(l-1)*l*(2*l-1))/6);
        tr[k].f+=w;
    }
    void down(int k)
    {
        change((k<<1),tr[k].f);
        change((k<<1|1),tr[k].f);
        tr[k].f=0;
    }
    void build(int k,int l,int r)
    {
        tr[k].l=l;tr[k].r=r;
        if(l==r)
        {
            tr[k].f=tr[k].s.si=tr[k].s.sii=tr[k].s.s=0;
            return ;
        }
        int mid=(l+r)>>1;
        build(k<<1,l,mid);build(k<<1|1,mid+1,r);
        tr[k].s=tr[k<<1].s+tr[k<<1|1].s;
    }
    node ask(int k,int x,int y)
    {
        //cout<<tr[k].l<<" "<<tr[k].r<<" "<<x<<" "<<y<<" "<<tr[k].s.s<<endl;
        int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1;
        if(tr[k].f) down(k);
        if(x==l&&r==y) return tr[k].s;
        if(y<=mid) return ask(k<<1,x,y);
        else if(x>mid) return ask(k<<1|1,x,y);
        return ask(k<<1,x,mid)+ask(k<<1|1,mid+1,y);
    }
    void add(int k,int x,int y,int w)
    {
        //cout<<k<<" "<<x<<" "<<y<<" "<<tr[k].s.s<<endl;
        int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1;
        if(tr[k].f) down(k);
        if(x==l&&r==y)
        {
            change(k,w);
            return;
        }
        if(y<=mid) add(k<<1,x,y,w);
        else if(x>mid) add(k<<1|1,x,y,w);
        else add(k<<1,x,mid,w),add(k<<1|1,mid+1,y,w);
        tr[k].s=tr[k<<1].s+tr[k<<1|1].s;
    }
    ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
    signed main()
    {
        //freopen("data.in","r",stdin);
        //freopen("data.out","w",stdout);
        int n=rd()-1,m=rd();ll ans=0,len,d;
        char op[2];
        build(1,1,n);
        for(int i=1,x,y,z;i<=m;i++)
        {
            scanf("%s",op);
            if(op[0]=='C')
            {
                x=rd(),y=rd()-1,z=rd();
                //cout<<i<<" "<<x<<" "<<y<<endl;
                add(1,x,y,z);
            //    cout<<ask(1,31,39).s<<endl;
                continue;
            }
            if(op[0]=='Q')
            {
                x=rd(),y=rd()-1;
            //    cout<<x<<" "<<y<<endl;
                node tmp=ask(1,x,y);
                ans=(tmp.si*(x+y)-tmp.sii-1ll*(x-1)*(y+1)*tmp.s);
                //cout<<ask(1,1,2).s<<endl;
                //cout<<tmp.s<<" "<<tmp.si*(x+y)<<" "<<tmp.sii<<" "<<(x-1)*(y+1)*tmp.s<<endl;
                len=1ll*(y-x+2)*(y-x+1)/2;
                if(ans==0) puts("0/1");
                else d=gcd(ans,len),printf("%lld/%lld
    ",ans/d,len/d);
            }
        }
    }
    /*
    g++ 1.cpp -o 1
    ./1
    4 5
    C 1 4 2
    C 1 2 -1
    Q 1 2
    Q 2 4
    Q 1 4
    */
    View Code
    Zeit und Raum trennen dich und mich.时空将你我分开。
  • 相关阅读:
    idea从maven导入jar包
    java zip4j压缩打包zip
    three.js一步一步来--如何画出一个逃跑的圆柱体
    three.js一步一步来--如何用线画出一个面--网格板子
    three.js一步一步来--如何画出一个转动的正方体
    three.js一步一步来--如何画出一根线
    假如你想在VUE的main.js里根据条件按需引入注册组件以及样式,那就这样子写,附赠自己写的vue一个框架配置多系统按需加载系统路由以及组件办法
    React Hook 的底层实现原理
    测试Markdown
    Linux学习总结(十六)系统用户及用户组管理
  • 原文地址:https://www.cnblogs.com/starsing/p/11239139.html
Copyright © 2011-2022 走看看