【题解】HAOI2012高速公路

  一节政治课的结果……推式子+推式子+推式子……

  首先注意到一个区间里面,选择(x, y)和(y, x)的费用是一样的。所以我们把这两种情况合为一种,那么现在询问的区间为(l, r),则一共的情况就有 1 / (k + 1)*(k)种 (k = r - l + 1)。所以我们只需要求出区间内所有的子集之和 * 2 / (k + 1) * k(每种情况有两种)。但这样复杂度还是太高了,我们考虑继续推下式子。

  顺着一个比较常见的思路想:分离出每一段路对于答案的贡献再累加起来。那么我们的ans = Vx(这一段路的代价) * 包含了这条道路的区间个数。包含了第x条道路的区间个数一共是(x - l + 1) * (r - x)。但这个东西我们不好维护,所以将它拆分一下,尽量分离出不变的量。这个东西就等于:((rx + lx) - (x * x + x) + (r - l * r))* Vx。由此, 问题转化为维护区间内的 Vx 之和, Vx * x之和, 与 Vx * x * (x + 1)之和。线段树完美解决!

// luogu-judger-enable-o2
#include <bits/stdc++.h>
using namespace std;
#define maxn 100005
#define int unsigned long long
int n, m, mark[maxn * 3];

struct tree
{
    int l, r, num[4], size, x, xx;
}T[maxn * 40];

int read()
{
    int x = 0, k = 1;
    char c;
    c = getchar();
    while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * k;
}

void Build(int p, int l, int r)
{
    T[p].l = l, T[p].r = r, T[p].size = (r - l + 1);
    if(l == r)
    {
        T[p].num[1] = T[p].num[2] = T[p].num[3] = 0;
        T[p].x = l, T[p].xx = T[p].x * (T[p].x + 1);
        return;
    }
    int mid = (l + r) >> 1;
    Build(p << 1, l, mid), Build(p << 1 | 1, mid + 1, r);
    T[p].x = T[p << 1].x + T[p << 1 | 1].x;
    T[p].xx = T[p << 1].xx + T[p << 1 | 1].xx;
    return;
}

void push_up(int p, int num)
{
    T[p].num[1] += num * T[p].x;
    T[p].num[2] += num * T[p].xx;
    T[p].num[3] += num * T[p].size;
    mark[p] += num;
}

void push_down(int p)
{
    if(!mark[p]) return;
    push_up(p << 1, mark[p]);
    push_up(p << 1 | 1, mark[p]);
    mark[p] = 0;
}

void update(int p, int l, int r, int num) // num1 :Vx * x, num2 :Vx * x * (x + 1), num3 : Vx; 
{
    int mid = (l + r) >> 1;
    int L = T[p].l, R = T[p].r;
    if(L >= l && R <= r)
    {
        push_up(p, num);
        return;
    }
    if(R < l || L > r) return;
    push_down(p);
    update(p << 1, l, r, num), update(p << 1 | 1, l, r, num);
    T[p].num[1] = T[p << 1].num[1] + T[p << 1 | 1].num[1];
    T[p].num[2] = T[p << 1].num[2] + T[p << 1 | 1].num[2];
    T[p].num[3] = T[p << 1].num[3] + T[p << 1 | 1].num[3];
}

int query(int p, int l, int r, int opt)
{
    int L = T[p].l, R = T[p].r;
    if(R < l || L > r) return 0;
    if(L >= l && R <= r) return T[p].num[opt];
    push_down(p);
    return query(p << 1, l, r, opt) + query(p << 1 | 1, l, r, opt);
}

int Get(int a, int b)
{
    while(b)
    {
        int c = a % b;
        a = b;
        b = c;
    }
    return a;
}

signed main()
{
    n = read(), m = read();
    Build(1, 1, n);
    for(int i = 1; i <= m; i ++)
    {
        char c;
        cin >> c;
        int l = read(), r = read();
        if(c == 'C')
        {
            int v = read();
            update(1, l, r - 1, v);
        }
        else // num1 :Vx * x, num2 :Vx * x * (x + 1), num3 : Vx; 
        {
            int ans = query(1, l, r - 1, 1) * (l + r);
            ans -= query(1, l, r - 1, 2);
            ans += query(1, l, r - 1, 3) * (r - l * r);
            int K = (r - l + 1) * (r - l);
            int GCD = Get(ans * 2, K);
            printf("%lld/%lld\n", ans * 2 / GCD, K / GCD); 
        }
    }
    return 0;
}

 

posted @ 2018-03-13 15:43  Twilight_Sx  阅读(157)  评论(0编辑  收藏  举报