【填坑/xdoj难题集】xdoj 2018校赛 现场赛 I(xdoj1297) Tr0y And His Startup

又是一个坑,之前的文章里也说过是因为不知道为什么会得到个样例从而弃坑的,现在看来原来是不知道分数取模,真的有点惨,除去这点之后这道题的思路基本和我当时想的一模一样,维护一个能够查询区间和区间平方和的线段树,然后进行一些小计算即可,鉴于我比较懒,所以直接从网上抄了一个自认为不错的,然后复刻封装了一下,之后又犯了一些低级错误debug了一阵,从而解决了这个问题。
简单说说题目,求每次攻击后的流量期望并不断做区间加法,期望流量考虑单点,假如永远会引流,那么期望就是(C + 1) / 2然而很多时候系统可以自己解决,而这些流量的离散和正好是1加到x - 1即x(x - 1)那么把这个除C就是减小的部分了,所以这道题基本就解决了,算出区间和和区间平方和,然后常数乘r - l + 1就是区间的结果了。

贴代码

# include <cstdio>
# include <algorithm>

using namespace std;

namespace tree
{
    # define ini int mid = (l + r) >> 1, kl = k << 1 | 1, kr = (k << 1) + 2

    const int Mod = 1e9 + 7;
    const int MAX_N = 3e5;
    typedef long long ll;

    ll A[MAX_N / 3];
    //ll maxx[MAX_N], minn[MAX_N];
    ll val[MAX_N], v2[MAX_N];
    ll x[MAX_N];

    inline void check(ll &a)
    {
        a >= Mod ? a = a - Mod : a;
    }

    void up(int k , int l , int r)
    {
        ini;
        val[k] = val[kl] + val[kr];
        v2[k] = v2[kl] + v2[kr];

        check(val[k]);
        check(v2[k]);
        //maxx[k] = max(maxx[kl] , maxx[kr]);
        //minn[k] = min(minn[kl] , minn[kr]);
    }

    void down(int k , int l , int r)
    {
        if(r - l == 1)
            return;
        ini;

        if(x[k])
        {
            x[kl] += x[k];
            x[kr] += x[k];
            v2[kl] += ((mid - l) * x[k] % Mod * x[k] % Mod + 2 * val[kl] * x[k] % Mod) % Mod;
            v2[kr] += ((r - mid) * x[k] % Mod * x[k] % Mod + 2 * val[kr] * x[k] % Mod) % Mod;
            val[kl] += (mid - l) * x[k] % Mod;
            val[kr] += (r - mid) * x[k] % Mod;

            check(x[kl]);
            check(x[kr]);
            check(v2[kl]);
            check(v2[kr]);
            check(val[kl]);
            check(val[kr]);
            //maxx[kl] += x[k];
            //maxx[kr] += x[k];
            //minn[kl] += x[k];
            //minn[kr] += x[k];
        }

        x[k] = 0;
    }

    void cons(int k , int l , int r)
    {
        if(r - l == 1)
        {
            x[k] = 0;
            val[k] = A[l];
            v2[k] = A[l] * A[l] % Mod;
            return;
        }

        ini;
        cons(kl , l , mid);
        cons(kr , mid , r);
        up(k , l , r);
    }

    void add(int k , int l , int r , int a , int b , int v)
    {
        if(a <= l && r <= b)
        {
            v2[k] += ((ll)(r - l) * v % Mod * v % Mod + 2 * v * val[k] % Mod) % Mod;
            val[k] += (ll)(r - l) * v % Mod;
            //maxx[k] += v;
            // minn[k] += v;
            x[k] += v;

            check(v2[k]);
            check(val[k]);
            check(x[k]);

            return;
        }

        down(k , l , r);

        ini;
        if(a < mid)
            add(kl , l , mid , a , b , v);
        if(mid < b)
            add(kr , mid , r , a , b , v);

        up(k , l , r);
    }

    void ques(int k , int l , int r , int a , int b , ll &q1 , ll &q2)
    {
        if(a <= l && r <= b)
        {
            q1 += val[k];
            q2 += v2[k];

            check(q1);
            check(q2);
            return; 
        }

        ini;
        down(k , l , r);

        if(a < mid)
            ques(kl , l , mid , a , b , q1 , q2);
        if(mid < b)
            ques(kr , mid , r , a , b , q1 , q2);

        up(k , l , r);
    }
}

using tree::check;
using tree::cons;
using tree::add;
using tree::ques;
using tree::A;//??
using tree::ll;
using tree::Mod;

ll po(ll a , ll b , ll mo)
{
    ll ans = 1;
    while(b)
    {
        if(b & 1)
            ans = ans * a % mo;

        b >>= 1;
        a = a * a % mo;
    }

    return ans;
}

inline ll ni(ll a)
{
    return po(a , Mod - 2 , Mod);
}

int N, C, Q; 
int nC, n2;

int main()
{
    scanf("%d %d %d", &N, &C, &Q);

    nC = ni(C);
    n2 = ni(2);

    int i;
    for(i = 0 ; i < N ; i++)
        scanf("%d", &A[i]);

    cons(0 , 0 , N);

    int l, r, q;
    for(i = 0 ; i < Q ; i++)
    {
        scanf("%d %d %d", &l, &r, &q);
        l--;

        ll q1 = 0, q2 = 0;
        ques(0 , 0 , N , l , r , q1 , q2);
        //printf("%lld %lld\n", q1, q2);
        ll ans = (q1 + Mod - q2) % Mod;
        ans = ans * n2 % Mod * nC % Mod;
        ans += (ll)(r - l) * (C + 1) % Mod * n2 % Mod;

        check(ans);
        printf("%lld\n", ans);

        add(0 , 0 , N , l , r , q);
    }

    return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值