Turing Tree (offline query + segment tree / tree array or chairman tree)

Posted by Zippyaus on Fri, 11 Feb 2022 00:17:29 +0100

Title Link: Turing Tree

General meaning

There is a sequence of length n, numbered from 1 to n, and each position has an element value

Query: multiple queries, the sum of elements after de duplication in each query [l, r]

Problem solving ideas

Offline query + segment tree / tree array or chairman tree

Acacia topic recommendation

Solution 1: Chairman tree

The idea of chairman tree is actually more imaginative The essence of this question is to ask each interval and find the sum of non repeated elements Then we build a line segment tree according to each position, and maintain the sum of non repeating elements in the [1, index] position in the tree

When added to the index position, there are two situations: ① the number has not appeared before; ② the number has appeared in pos position before (pos < index) (for the maintenance of pos location, we can use hash table)

For case ①, we can make normal statistics In case ②, we also need to update the current point, but we also need to delete the contribution of the previous point, which is equivalent to + Val in the index position and - Val in the POS position (Val is the value of the current position) So why should we do this?

Considering that it is already the segment tree of the index version, the query interval we need to deal with is [l, index]. Obviously, the number appearing in the pos position can only ensure the contribution in the [1, pos] interval, while the [pos + 1, index] interval cannot produce the contribution, Therefore, the contribution of this interval will be less than val. and the number appearing in the index position can ensure the contribution in the query interval Therefore, the contribution at the index position is better than that at the pos position. In addition, considering the prevention of double calculation of contribution in the [1, pos] interval, it is necessary to calculate the contribution at the pos position - Val and the index position + val

In this way, when we query the [l, r] interval, we can directly query [l, r] * * in * * the r-th line segment tree Considering the optimization space, the chairman tree is adopted

Solution 2: offline query + line segment tree (tree array)

The core of this idea is the idea of offline query. Segment tree and tree array are only for maintaining interval contribution

We consider storing all queries and sorting them from small to large according to the right endpoint r
When processing queries, we assume a pos variable, which indicates that the first pos positions have been maintained in the current tree. Each time, we let pos maintain to the right bound r of the current query, so as to ensure that the interval maintained in the tree is [1, r]

Similar to the idea of the chairman tree, there are two cases when we add it to the pos position The idea is the same

For the query [l, r], we can directly query the [l, r] interval in the tree

AC code

/* Chairman tree */
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
const int N = 3E4 + 10;
struct node {
	int l, r;
	ll val;
}t[N << 5];
int root[N], ind;
int build(int a, int c, int tl, int tr, int p) {
	int x = ++ind; t[x] = t[p];
	t[x].val += c;
	if (tl == tr) return x;
	int mid = tl + tr >> 1;
	if (a <= mid) t[x].l = build(a, c, tl, mid, t[p].l);
	else t[x].r = build(a, c, mid + 1, tr, t[p].r);
	return x;
}
ll ask(int l, int r, int tl, int tr, int x) {
	if (l <= tl and r >= tr) return t[x].val;
	int mid = tl + tr >> 1;
	ll res = 0;
	if (l <= mid) res = ask(l, r, tl, mid, t[x].l);
	if (r > mid) res += ask(l, r, mid + 1, tr, t[x].r);
	return res;
}
int main()
{
	int T; cin >> T;
	while (T--) {
		ind = 0;

		unordered_map<int, int> mp;
		int n; scanf("%d", &n);
		rep(i, n) {
			int x; scanf("%d", &x);
			root[i] = build(i, x, 1, n, root[i - 1]);
			if (mp.count(x)) root[i] = build(mp[x], -x, 1, n, root[i]);
			mp[x] = i;
		}

		int m; scanf("%d", &m);
		rep(i, m) {
			int l, r; scanf("%d %d", &l, &r);
			printf("%lld\n", ask(l, r, 1, n, root[r]));
		}
	}
	return 0;
}



/* Offline query + tree array */
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
const int N = 3E4 + 10, M = 1E5 + 10;
int w[N];

struct operation {
	int l, r, id;
	bool operator< (const operation& t) const { return r < t.r; }
}; vector<operation> area;


ll t[N], res[M];
int lowbit(int x) { return x & -x; }
void add(int x, int c) { for (int i = x; i < N; i += lowbit(i)) t[i] += c; }
ll ask(int x) {
	ll res = 0;
	for (int i = x; i; i -= lowbit(i)) res += t[i];
	return res;
}
ll ask(int l, int r) { return ask(r) - ask(l - 1); }
int main()
{
	int T; cin >> T;
	while (T--) {
		area.clear(); memset(t, 0, sizeof t);

		int n; scanf("%d", &n);
		rep(i, n) scanf("%d", &w[i]);

		int m; scanf("%d", &m);
		rep(i, m) {
			int l, r; scanf("%d %d", &l, &r);
			area.push_back({ l, r, i });
		}
		sort(area.begin(), area.end());

		unordered_map<int, int> mp;
		int pos = 0;
		for (auto& op : area) {
			int l = op.l, r = op.r, id = op.id;
			while (pos + 1 <= r) {
				++pos;
				add(pos, w[pos]);
				if (mp.count(w[pos])) add(mp[w[pos]], -w[pos]);
				mp[w[pos]] = pos;
			}
			res[id] = ask(l, r);
		}

		rep(i, m) printf("%lld\n", res[i]);
	}
	return 0;
}

END

Topics: Algorithm data structure ICPC