P11217 【MX-S4-T1】「yyOI R2」youyou 的垃圾桶

P11217 【MX-S4-T1】「yyOI R2」youyou 的垃圾桶 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

实际上整理整理没什么难的。主要是考数据结构,完了时间复杂度 \(O(n\log^2n)\) 的树状数组 + 二分,比 \(O(n\log n)\) 的线段树上二分还快,而且线段树还差 20ms 就爆了,线段树还是得优化常数。

通过推公式,二分找出经过 k 轮(全部都使用),能把血量清零。然后 k - 1, 去找最后一轮实际上用多少,这里主要是求 sum 与 二分,所以可以使用线段树上二分,或者树状数组求和 + 二分。

附上测评结果:
树状数组: 记录详情 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
线段树(不卡常):记录详情 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
线段树(卡常):记录详情 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

树状数组 + 二分

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <ctime>

using namespace std;

typedef long long LL;

const int N = 200010;

LL n, m, w;
LL tr[N], trs[N];
LL a[N];


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

int lowbit(int x)
{
    return x & -x;
}

void add(LL tr[], int x, LL k)
{
    for (int i = x; i <= n; i += lowbit(i)) tr[i] += k;
}

void addd(int l, int r, LL k)
{
    add(tr, l, k);
    add(tr, r + 1, -k);
    add(trs, l, l * k);
    add(trs, r + 1, -(r + 1) * k);
}


LL sum(LL tr[], int x)
{
    LL res = 0;
    for (int i = x; i; i -= lowbit(i)) res += tr[i];
    return res;
}

LL ssum(int x)
{
    LL a = sum(tr, x), b = sum(trs, x);
    return (__int128)a * (x + 1) - b;
}

LL find(LL x, LL sum)
{
    LL l = 0, r = 61;
    
    while (l < r)
    {
        LL mid = l + r >> 1;
        if ((__int128)sum * ((1ll << mid) - 1) >= x) r = mid;
        else l = mid + 1;
    }
    return l;
}

LL find2(LL w, LL k)
{
    int l = 0, r = n;
    
    while (l < r)
    {
        int mid = l + r >> 1;
        if ((__int128)ssum(mid) * (1ll << k) >= w) r = mid;
        else l = mid + 1;
    }
    return l;
}

int main()
{
// 	freopen("wxyt4.in", "r", stdin);
// 	freopen("wxyt4.out", "w", stdout);

    cin >> n >> m >> w;
    
    for (int i = 1; i <= n; i ++ )
    {
        a[i] = read();
        add(tr, i, a[i] - a[i - 1]);
        add(trs, i, 1ll * i * (a[i] - a[i - 1]));
    }
    
    LL last = ssum(n);
    while (m -- )
    {
        LL l, r, d;
        l = read();
        r = read();
        d = read();
        addd(l, r, d);
        last += (r - l + 1) * d;
        LL res = last, ans = 0;
        LL k = find(w, res) - 1;
        ans = k * n; 
        ans += find2(w - res * ((1ll << k) - 1), k) - 1;
        printf("%lld\n", ans);
    }
    
    return 0;
}

线段树上二分

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <ctime>


using namespace std;

typedef long long LL;

const int N = 200010;

LL n, m, w;
LL a[N];

struct Node 
{
    int l, r;
    __int128 sum, add;
}tr[N * 4];

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


void pushup(Node &u, Node &l, Node &r)
{
    u = {l.l, r.r, l.sum + r.sum};
}

void pushup(int u)
{
    pushup(tr[u], tr[u << 1], tr[u << 1 | 1]);
}

void pushdown(Node &u, LL add)
{
    u.sum += (u.r - u.l + 1) * add;
    u.add += add;
}

void pushdown(int u)
{
    pushdown(tr[u << 1], tr[u].add);
    pushdown(tr[u << 1 | 1], tr[u].add);
    tr[u].add = 0;
}

void build(int u, int l, int r)
{
    if (l == r) tr[u] = {l, r, a[l]};
    else
    {
        tr[u] = {l, r};
        int mid = l + r >> 1;
        build(u << 1, l, mid);
        build(u << 1 | 1, mid + 1, r);
        pushup(u);
    }
}

void modify(int u, int l, int r, int add)
{
    if (l <= tr[u].l && tr[u].r <= r) pushdown(tr[u], add);
    else
    {
        pushdown(u);
        int mid = tr[u].l + tr[u].r >> 1;
        if (l <= mid) modify(u << 1, l, r, add);
        if (r > mid) modify(u << 1 | 1, l, r, add);
        pushup(u);
    }
}

LL query(int u, int l, int r)
{
    if (l <= tr[u].l && tr[u].r <= r) return tr[u].sum;
    else
    {
        pushdown(u);
        int mid = tr[u].l + tr[u].r >> 1;
        LL sum = 0;
        if (l <= mid) sum += query(u << 1, l, r);
        if (r > mid) sum += query(u << 1 | 1, l, r);
        return sum;
    }
}

LL findl(int u, int l, int r, LL k, LL w, LL sum)
{
    if (tr[u].l == tr[u].r) 
    {
        if ((__int128)(tr[u].sum + sum) * k < w) return -1;
        return tr[u].l;
    }
    else if (l <= tr[u].l && tr[u].r <= r)
    {
    	pushdown(u);
        if ((__int128)(tr[u << 1].sum + sum) * k >= w) return findl(u << 1, l, r, k, w, sum);
        else return findl(u << 1 | 1, l, r, k, w, sum + tr[u << 1].sum);
    }
}

LL find(LL x, LL sum)
{
    LL l = 0, r = 61;
    
    while (l < r)
    {
        LL mid = l + r >> 1;
        if ((__int128)sum * ((1ll << mid) - 1) >= x) r = mid;
        else l = mid + 1;
    }
    return l;
}

signed main()
{
//  	freopen("wxyt4.in", "r", stdin);
//  	freopen("wxyt4.out", "w", stdout);

    cin >> n >> m >> w;
    
    for (int i = 1; i <= n; i ++ )
    {
        a[i] = read();
    }
    
    build(1, 1, n);
    LL last = query(1, 1, n);
    while (m -- )
    {
        LL l, r, d;
        l = read();
        r = read();
        d = read();
        modify(1, l, r, d);
        last += 1ll * (r - l + 1) * d;
        LL res = last, ans = 0;
        LL k = find(w, res) - 1;
        ans = k * n; 
        ans += findl(1, 1, n, (1ll << k), w - res * ((1ll << k) - 1), 0) - 1;
        printf("%lld\n", ans);
    }
    
    return 0;
}
posted @ 2024-11-10 22:12  blind5883  阅读(2)  评论(0编辑  收藏  举报