洛谷 P2221 [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

输入输出样例

输入样例#1:
4 5
C 1 4 2
C 1 2 -1
Q 1 2
Q 2 4
Q 1 4
输出样例#1:
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

分析:
两个高速站中间的费用我们可以看做一个数,那么询问 [ l , r ] 之间的和相当于询问第 l 到第 r 1 个数的和,这样会方便一些。

我们考虑答案可以由总贡献除以事件个数求得,主要就是求总贡献。

我们考虑每一个数的贡献,显然当一个区间跨越了这一个数时,也就是一个端点在左边,另一个端点再右边,这个数便有贡献(我们设的数时两个高速站的费用,所以取 [ l , l ] 这种区间其实在高速上是不同的两个点,可以存在)。

那么,显然有,

s u m [ l ] [ r ] = i = l r w i ( i l + 1 ) ( r i + 1 )

= i = l r w i ( i 2 + ( l + r ) i + ( r + 1 ) ( 1 l ) )

根据分配率化简一下,
= i = 1 r w i i 2 + i = 1 r w i ( l + r ) i + i = l r w i ( r + 1 ) ( 1 l )

整理一下可得,
s u m [ i ] [ j ] = ( r + 1 ) ( 1 l ) i = l r w i + ( l + r ) i = 1 r w i i i = 1 r w i i 2

因为有区间修改,可以用线段树把 i = l r w i i = 1 r w i i i = 1 r w i i 2 维护一下。
其中,选择方案数为 ( r l + 2 ) ( r l + 1 ) 2 ,平方和公式为 n ( n + 1 ) ( 2 n + 1 ) 6
由于一开始推错了式子,所以代码中 i = l r w i 放到了最后面。

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>

const int maxn=1e5+7;

using namespace std;

typedef long long LL;

struct node{
    LL sum1,sum2,sum3;
    LL lazy1,lazy2,lazy3;
}t[maxn*4];

int n,m,l,r;
LL x;
char s[1];

LL getsum_power1(int l,int r)
{
    return (LL)(l+r)*1ll*(r-l+1)/2;
}

void add1(int p,int l,int r,int x,int y,LL k)
{
    if ((l==x) && (r==y))
    {
        t[p].lazy1+=k;
        t[p].sum1+=getsum_power1(l,r)*k;
        return;
    }
    int mid=(l+r)/2;
    if (t[p].lazy1)
    {
        t[p*2].lazy1+=t[p].lazy1;
        t[p*2].sum1+=getsum_power1(l,mid)*t[p].lazy1;
        t[p*2+1].lazy1+=t[p].lazy1;
        t[p*2+1].sum1+=getsum_power1(mid+1,r)*t[p].lazy1;
        t[p].lazy1=0;
    }
    if (y<=mid) add1(p*2,l,mid,x,y,k);
    else
    {
        if (x>mid) add1(p*2+1,mid+1,r,x,y,k);
        else
        {
            add1(p*2,l,mid,x,mid,k);
            add1(p*2+1,mid+1,r,mid+1,y,k);
        }
    }
    t[p].sum1=t[p*2].sum1+t[p*2+1].sum1;
}

LL getsum_power2(int l,int r)
{
    return (LL)(r*1ll*(r+1)*1ll*(2*r+1)-l*1ll*(l-1)*1ll*(2*l-1))/6;
}

void add2(int p,int l,int r,int x,int y,LL k)
{
    if ((l==x) && (r==y))
    {
        t[p].lazy2+=k;
        t[p].sum2+=getsum_power2(l,r)*k;
        return;
    }
    int mid=(l+r)/2;
    if (t[p].lazy2)
    {
        t[p*2].lazy2+=t[p].lazy2;
        t[p*2].sum2+=getsum_power2(l,mid)*t[p].lazy2;
        t[p*2+1].lazy2+=t[p].lazy2;
        t[p*2+1].sum2+=getsum_power2(mid+1,r)*t[p].lazy2;
        t[p].lazy2=0;
    }
    if (y<=mid) add2(p*2,l,mid,x,y,k);
    else
    {
        if (x>mid) add2(p*2+1,mid+1,r,x,y,k);
        else
        {
            add2(p*2,l,mid,x,mid,k);
            add2(p*2+1,mid+1,r,mid+1,y,k);
        }
    }
    t[p].sum2=t[p*2].sum2+t[p*2+1].sum2;
}

LL getsum1(int p,int l,int r,int x,int y)
{
    if ((l==x) && (r==y)) return t[p].sum1;
    int mid=(l+r)/2;
    if (t[p].lazy1)
    {
        t[p*2].lazy1+=t[p].lazy1;
        t[p*2].sum1+=getsum_power1(l,mid)*t[p].lazy1;
        t[p*2+1].lazy1+=t[p].lazy1;
        t[p*2+1].sum1+=getsum_power1(mid+1,r)*t[p].lazy1;
        t[p].lazy1=0;
    }
    if (y<=mid) return getsum1(p*2,l,mid,x,y);
    else
    {
        if (x>mid) return getsum1(p*2+1,mid+1,r,x,y);
              else return getsum1(p*2,l,mid,x,mid)+getsum1(p*2+1,mid+1,r,mid+1,y);
    }
}

LL getsum2(int p,int l,int r,int x,int y)
{
    if ((l==x) && (r==y)) return t[p].sum2;
    int mid=(l+r)/2;
    if (t[p].lazy2)
    {
        t[p*2].lazy2+=t[p].lazy2;
        t[p*2].sum2+=getsum_power2(l,mid)*t[p].lazy2;
        t[p*2+1].lazy2+=t[p].lazy2;
        t[p*2+1].sum2+=getsum_power2(mid+1,r)*t[p].lazy2;
        t[p].lazy2=0;
    }
    if (y<=mid) return getsum2(p*2,l,mid,x,y);
    else
    {
        if (x>mid) return getsum2(p*2+1,mid+1,r,x,y);
              else return getsum2(p*2,l,mid,x,mid)+getsum2(p*2+1,mid+1,r,mid+1,y);
    }
}

void add3(LL p,LL l,LL r,LL x,LL y,LL k)
{
    if ((l==x) && (r==y))
    {
        t[p].lazy3+=k;
        t[p].sum3+=(r-l+1)*k;
        return;
    }
    LL mid=(l+r)/2;
    if (t[p].lazy3)
    {
        t[p*2].lazy3+=t[p].lazy3;
        t[p*2+1].lazy3+=t[p].lazy3;
        t[p*2].sum3+=(mid-l+1)*1ll*t[p].lazy3;
        t[p*2+1].sum3+=(r-mid)*1ll*t[p].lazy3;
        t[p].lazy3=0;
    }
    if (y<=mid) add3(p*2,l,mid,x,y,k);
    else if (x>mid) add3(p*2+1,mid+1,r,x,y,k);
        else
        {
            add3(p*2,l,mid,x,mid,k);
            add3(p*2+1,mid+1,r,mid+1,y,k);
        }
    t[p].sum3=t[p*2].sum3+t[p*2+1].sum3; 
}

LL getsum3(int p,int l,int r,int x,int y)
{
    if ((l==x) && (r==y)) return t[p].sum3;
    LL mid=(l+r)/2;
    if (t[p].lazy3)
    {
        t[p*2].lazy3+=t[p].lazy3;
        t[p*2+1].lazy3+=t[p].lazy3;
        t[p*2].sum3+=(mid-l+1)*1ll*t[p].lazy3;
        t[p*2+1].sum3+=(r-mid)*1ll*t[p].lazy3;
        t[p].lazy3=0;
    }
    if (y<=mid) return getsum3(p*2,l,mid,x,y);
    else if (x>mid) return getsum3(p*2+1,mid+1,r,x,y);
        else return getsum3(p*2,l,mid,x,mid)+getsum3(p*2+1,mid+1,r,mid+1,y);
}

LL gcd(LL x,LL y)
{
    LL r=x%y;
    while (r)
    {
        x=y;
        y=r;
        r=x%y;
    }
    return y;
}

int main()
{
    scanf("%d%d",&n,&m);
    n--;
    for (int i=1;i<=m;i++)
    {
        scanf("%s",s);      
        if (s[0]=='C')
        {
            scanf("%d%d%lld",&l,&r,&x);
            add1(1,1,n,l,r-1,x);
            add2(1,1,n,l,r-1,x);
            add3(1,1,n,l,r-1,x);
        }
        else
        {
            scanf("%d%d",&l,&r);
            LL y=(LL)(r-l)*1ll*(r-l+1)/2;
            r=r-1;
            LL ans=(LL)(r+1)*(1-l)*getsum3(1,1,n,l,r)+(l+r)*1ll*getsum1(1,1,n,l,r)-getsum2(1,1,n,l,r);
            LL x=ans;           
            LL d=gcd(x,y);
            x/=d;
            y/=d;
            printf("%lld/%lld\n",x,y);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/liangzihao1/article/details/81072239