Title

NC23054.华华开始学信息学

NC23054.华华开始学信息学

分块 树状数组

第一次接触分块,感觉好美腻

思路

最直接的思路:树状数组暴力修改

神奇的代码
int fenwick[maxn];
int n = 0, m = 0;

void modify(int pos, int x)
{
    while(pos <= n)
    {
        fenwick[pos] += x;
        pos += lowbit(pos);
    }
}

int query(int pos)
{
    int res = 0;
    while(pos)
    {
        res += fenwick[pos];
        pos -= lowbit(pos);
    }   
    return res;
}

int range_query(int l, int r)
{
    return query(r) - query(l - 1);
}

void solve()
{
    std::cin >> n >> m;
    int tmp = 0;
    int op = 0, x = 0, y = 0;
    while(m--)
    {
        std::cin >> op >> x >> y;
        if (op == 1)
        {
            for (int i = x; i <= n; i += x)
            {
                modify(i, y);
            }
        }
        else
        {
            std::cout << range_query(x, y) << endl;
        }
    }
}

复杂度爆炸

原因是\(D\)很小的时候需要修改很多次

那怎么办呢?考虑用一个懒标记记录下来\(lazy[D] += k\),等到查询的时候在加上去

神奇的代码
int fenwick[maxn], lazy[maxn];
int n = 0, m = 0;

void modify(int pos, int x)
{
    while(pos <= n)
    {
        fenwick[pos] += x;
        pos += lowbit(pos);
    }
}

int query(int pos)
{
    int res = 0;
    while(pos)
    {
        res += fenwick[pos];
        pos -= lowbit(pos);
    }   
    return res;
}

int range_query(int l, int r)
{
    return query(r) - query(l - 1);
}

void solve()
{
    std::cin >> n >> m;
    int tmp = 0;
    int op = 0, x = 0, y = 0;
    while(m--)
    {
        std::cin >> op >> x >> y;
        if (op == 1)
        {
            lazy[x] += y;
        }
        else
        {
            int ans = range_query(x, y);
            for (int i = 1; i <= n; i++)
            {
                // 区间内有多少i的倍数
                ans += (y / i - (x - 1) / i) * lazy[i];
            }
            std::cout << ans << endl;
        }
    }
}

复杂度好像爆的更厉害了

原因是\(D\)很大的时候就又不行了

怎么办呢\(\rightarrow\)两个方法结合起来不就好了\(\rightarrow\)于是就有了分块的思想

\(\sqrt{n}\)为界限,如果\(D > \sqrt{n}\),就直接数组树状暴力修改,否则就用\(lazy\)标记

代码

神奇的代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
#define lowbit(x) x & -x;
const int maxn = 2e5 + 5;
const int inf = 0x7f7f7f7f;

int fenwick[maxn], lazy[maxn];
int n = 0, m = 0;

void modify(int pos, int x)
{
    while(pos <= n)
    {
        fenwick[pos] += x;
        pos += lowbit(pos);
    }
}

int query(int pos)
{
    int res = 0;
    while(pos)
    {
        res += fenwick[pos];
        pos -= lowbit(pos);
    }   
    return res;
}

int range_query(int l, int r)
{
    return query(r) - query(l - 1);
}

void solve()
{
    std::cin >> n >> m;
    int tmp = 0;
    int op = 0, x = 0, y = 0;
    while(m--)
    {
        std::cin >> op >> x >> y;
        if (op == 1)
        {
            if (x <= sqrt(n))
            {
                lazy[x] += y;
            }
            else
            {
                for (int i = x; i <= n; i += x)
                {
                    modify(i, y);
                }
            }
        }
        else
        {
            int ans = range_query(x, y);
            for (int i = 1; i <= sqrt(n); i++)
            {
                // 区间内有多少i的倍数
                ans += (y / i - (x - 1) / i) * lazy[i];
            }
            std::cout << ans << endl;
        }
    }
}

signed main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr); std::cout.tie(nullptr);
    //freopen("out.txt", "w", stdout);
    int t = 1;
    //std::cin >> t;
    while(t--)
    {
        solve();
    }
    return 0;
}

posted @ 2024-11-07 23:21  栗悟饭与龟功気波  阅读(7)  评论(0)    收藏  举报