树状数组

树状数组

逆序对

#include <iostream>
#include <cstring>
#include <algorithm>
#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 <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
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<j,a[i]<a[j]\)

本题求的是最长下降子序列

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
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 <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
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;
}

类模板

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>

using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
int n, q;
ll a[N];
template<class T>
struct BIT
{
	T tr[N];
	int size;
	void resize(int s) {size = s;}
	T query(int x)
	{
		T s = 0;
		for ( ; x; x -= x & -x)
			s += tr[x];
		return s;
	}
	void modify(int x, T s)
	{
		for ( ; x <= size; x += x & -x)
			tr[x] += s;
	}
};

BIT<ll> c;

树状数组上二分

http://oj.daimayuan.top/course/15/problem/636
若在权值上开树状数组,则可以求第 k 大的数 \(O(nlogn)\)

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>

using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
int n, q;
ll a[N];
template<class T>
struct BIT
{
	T tr[N];
	int size;
	void resize(int s) {size = s;}
	int query(T s)
	{
		int pos = 0;
		for (int j = 18; j >= 0; j--)
		{
			if (pos + (1 << j) <= n && tr[pos + (1 << j)] <= s)
			{
				pos += (1 << j);
				s -= tr[pos];
			}
		}
		return pos;
	}
	void modify(int x, T s)
	{
		for ( ; x <= size; x += x & -x)
			tr[x] += s;
	}
};

BIT<ll> c;

二维数点

http://oj.daimayuan.top/course/15/problem/686

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <array>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
int n, q, m;
int tr[N], ans[N];
vector<int> alls;
vector<array<int, 4> > event;

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

int query(int idx)
{
	int ans = 0;
	for (int i = idx; i; i -= lowbit(i))
		ans += tr[i];
	return ans;
}

void modify(int idx, int k)
{
	for (int i = idx; i <= m; i += lowbit(i))
		tr[i] += k;
}
int main()
{
	scanf("%d%d", &n, &q);
	for (int i = 1; i <= n; i++)
	{
		int x, y;
		scanf("%d%d", &x, &y);
		alls.push_back(x);
		event.push_back({y, 0, x});
	}
	for (int i = 1; i <= q; i++)
	{
		int x1, x2, y1, y2;
		scanf("%d%d%d%d", &x1, &x2, &y1, &y2);
		event.push_back({y2, 1, x2, i});
		event.push_back({y1 - 1, 2, x2, i});
		event.push_back({y2, 2, x1 - 1, i});
		event.push_back({y1 - 1, 1, x1 - 1, i});
	}
	
	sort(event.begin(), event.end());
	sort(alls.begin(), alls.end());
	alls.erase(unique(alls.begin(), alls.end()), alls.end());
	m = alls.size();
	
	for (auto evt : event)
	{
		if (evt[1] == 0)
		{
			int idx = lower_bound(alls.begin(), alls.end(), evt[2]) - alls.begin() + 1;
			modify(idx, 1);
		}
		else
		{
			int idx = upper_bound(alls.begin(), alls.end(), evt[2]) - alls.begin();
			if (evt[1] == 1)
				ans[evt[3]] += query(idx);
			else
				ans[evt[3]] -= query(idx);
		}
	}
	
	for (int i = 1; i <= q; i++)
		printf("%d\n", ans[i]);
	return 0;
}
posted @ 2022-05-16 23:56  hzy0227  阅读(23)  评论(0编辑  收藏  举报