2019广工校赛 D-免费送气球 (HDU6464)

直接上平衡树乱搞。
也可以离散化后线段树维护子树大小和区间和(平衡树不用离散化)
用的是Treap。

#include <cstdio>
#include <algorithm>
#include <cstdlib>

using namespace std;

typedef long long ll;
const ll maxn = 200005;
const ll mod = 1000000007;
ll ch[maxn][2], val[maxn], pri[maxn];
ll tot, rt;
ll siz[maxn], num[maxn], sum[maxn];
#define ls ch[now][0]
#define rs ch[now][1]

inline void pushUp(ll now)
{
    siz[now] = siz[ls] + siz[rs] + num[now];
    sum[now] = ((sum[ls] + sum[rs]) % mod + (val[now] * num[now]) % mod) % mod;
}

void rotate(ll &x, ll dir)
{
    ll son = ch[x][dir];
    ch[x][dir] = ch[son][dir ^ 1];
    ch[son][dir ^ 1] = x;
    pushUp(x);
    pushUp(x = son);
}

inline void newNode(ll v, ll cnt, ll &now)
{
    now = ++tot;
    ls = rs = 0;
    num[now] = siz[now] = cnt;
    val[now] = v;
    pri[now] = rand();
}

void insert(ll v, ll cnt, ll &now)
{
    if (!now)
    {
        newNode(v, cnt, now);
        sum[now] = v * cnt % mod;
        return;
    }
    if (val[now] == v)
    {
        num[now] += cnt;
        siz[now] += cnt;
        sum[now] = (sum[now] + cnt * v % mod) % mod;
        return;
    }
    if (v < val[now])
    {
        insert(v, cnt, ls);
        if (pri[ls] < pri[now])
            rotate(now, 0);
    }
    else
    {
        insert(v, cnt, rs);
        if (pri[rs] < pri[now])
            rotate(now, 1);
    }
    pushUp(now);
}

ll query(ll k, ll now)
{
    if (!k)
        return 0;
    if (siz[ls] < k && siz[ls] + num[now] >= k)
        return (sum[ls] + ((k - siz[ls]) * val[now]) % mod) % mod;
    else if (k <= siz[ls])
        return query(k, ls) % mod;
    else
        return ((sum[now] - sum[rs]) % mod + query(k - siz[ls] - num[now], rs)) % mod;
}

ll Q;

int main()
{
    scanf("%I64d", &Q);
    ll op;
    ll a, b;
    while (Q--)
    {
        scanf("%I64d%I64d%I64d", &op, &a, &b);
        if (op == 1)
            insert(b, a, rt);
        else
            printf("%I64d\n", ((query(b, rt) - query(a - 1, rt)) % mod + mod) % mod);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值