树状数组
树状数组
逆序对
#include
#include
#include
#define int long long
using namespace std;
const int N = 5e5 + 10;
int tr[N], ranks[N], n;
int ans;
struct point
{
int num, val;
bool operator<(const point &x) const
{
if (val == x.val)
return num < x.num;
return val < x.val;
}
}a[N];
int lowbit(int x)
{
return x & -x;
}
void add(int idx, int x)
{
for (int i = idx; i <= n; i += lowbit(i))
tr[i] += x;
}
int sum(int idx)
{
int s = 0;
for (int i = idx; i; i -= lowbit(i))
s += tr[i];
return s;
}
signed main()
{
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i].val, a[i].num = i;
sort(a + 1, a + n + 1);
for (int i = 1; i <= n; i++)
ranks[a[i].num] = i;
for (int i = 1; i <= n; i++)
{
add(ranks[i], 1);
ans += i - sum(ranks[i]);
}
cout << ans << endl;
return 0;
}
差分实现区间修改,单点查询
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
int n, m;
int tr[N];
int lowbit(int x)
{
return x & -x;
}
void add(int idx, int k)
{
for (int i = idx; i < N; i += lowbit(i))
tr[i] += k;
}
int sum(int idx)
{
int ans = 0;
for (int i = idx; i; i -= lowbit(i))
ans += tr[i];
return ans;
}
int main()
{
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n >> m;
while(m--)
{
int t;
cin >> t;
if (t == 1)
{
int l, r;
cin >> l >> r;
add(l, 1), add(r + 1, -1);
}
else
{
int x;
cin >> x;
cout << (sum(x) & 1) << endl;
}
}
return 0;
}
前缀最值 + 单点修改
利用二维偏序优化最长上升子序列 \(i
本题求的是最长下降子序列
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N = 1e6 + 10, INF = 1e9;
int n;
int a[N], f[N], tr[N];
int lowbit(int x)
{
return x & -x;
}
void update(int x, int k)
{
for (int i = x; i < N; i += lowbit(i))
tr[i] = max(tr[i], k);
}
int query(int x)
{
int ans = 0;
for (int i = x; i; i -= lowbit(i))
ans = max(ans, tr[i]);
return ans;
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
int ans = 1;
for (int i = 1; i <= n; i++)
tr[i] = 0;
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]), a[i] = n + 1 - a[i];//将逆序对变为正序对
for (int i = 1; i <= n; i++)
{
f[i] = query(a[i]) + 1;
update(a[i], f[i]);
ans = max(ans, f[i]);
}
printf("%d\n", ans);
for (int i = 1; i <= n; i++)
printf("%d ", f[i]);
puts("");
}
return 0;
}
二维树状数组
JSOI2009]计数问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N = 3e2 + 10;
int n, m, q;
int tr[N][N][110];
int a[N][N];
int lowbit(int x)
{
return x & -x;
}
void add(int x, int y, int c, int k)
{
for (int i = x; i < N; i += lowbit(i))
for (int j = y; j < N; j += lowbit(j))
tr[i][j][c] += k;
}
int sum(int x, int y, int c)
{
int ans = 0;
for (int i = x; i; i -= lowbit(i))
for (int j = y; j; j -= lowbit(j))
ans += tr[i][j][c];
return ans;
}
int main()
{
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
int x;
cin >> x;
a[i][j] = x;
add(i, j, x, 1);
}
}
cin >> q;
while(q--)
{
int op;
cin >> op;
if (op == 1)
{
int x, y, c;
cin >> x >> y >> c;
int last = a[x][y];
add(x, y, c, 1);
add(x, y, last, -1);
a[x][y] = c;
}
else
{
int x1, y1, x2, y2, c;
cin >> x1 >> x2 >> y1 >> y2 >> c;
cout << sum(x2, y2, c) - sum(x1-1, y2, c) - sum(x2, y1-1, c) + sum(x1-1, y1-1, c) << endl;
}
}
return 0;
}