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;
}

浙公网安备 33010602011771号