莫队

莫队

1、时间复杂度为 \(O(n\sqrt n)\),用于离线处理一些操作的答案。

template<typename T>
struct Md{
	struct Q {
		int L;
		int R;
		int num;
	};

	int n, m, k, len, l, r;
    T res;
	vector<Q> rs;
	vector<T> a, ans, pos, cnt;
	
	Md(int n_, int m_, int len_, int k_) : a(n_ + 1), ans(m_ + 1), pos(n_ + 1), cnt(k_ + 1) {
		l = 1;
        r = res = 0;
		n = n_;
		m = m_;
		len = len_;
        k = k_;
        init();
		action();
	}
	
	inline void init() {
		for (int i = 1; i <= n; i++) {
			cin >> a[i];
			pos[i] = (i - 1) / len + 1;
		}
		
		for (int i = 1; i <= m; i++) {
			int l, r;
			cin >> l >> r;
			rs.push_back({l, r, i});
		}
		
		sort(rs.begin(), rs.end(), [&](auto &x, auto &y) {
			return pos[x.L] == pos[y.L]
			? (x.R == y.R ? 0 : (pos[x.L] & 1) ^ (x.R < y.R))
			: x.L < y.L;
		});
	}
	
	inline void add(int x) {
        cnt[a[x]]++; res += cnt[a[x]] * 2 - 1;
    }
	
	inline void sub(int x) {
        cnt[a[x]]--; res -= cnt[a[x]] * 2 + 1;
    }
	
	inline void action() {
		for (auto [L, R, num] : rs) {
			while (L < l) add(--l);
			while (R > r) add(++r);
			while (L > l) sub(l++);
			while (R < r) sub(r--);
			ans[num] = res;
		}
	}
	
	inline void print_ans() {
		for (int i = 1; i <= m; i++) cout << ans[i] << '\n';
	}
};

void solve() {
	int n, m, k;
	read(n, m, k);
	int len = sqrt(n);
	Md<i64> t(n, m, len, k);
	t.print_ans();
}

带修莫队

1、时间复杂度为 \(O(n^\frac{5}{3})\)

template<typename T>
struct Cmd{
	struct Q {
		int L, R, num, tnum;
	};
	
	struct time_ {
		int pos, x;
	};
	
    int n, m, len, k, l, r, last;
    T res;
	vector<Q> rs;
	vector<time_> ts;
	vector<T> a, ans, mp;
	
	Cmd(int n_, int m_, int len_, int k_) : a(n_ + 1), ans(m_ + 1), mp(k_ + 1) {
		n = n_;
		m = m_;
		len = len_;
        k = k_;
		ts.push_back({0, 0});
		l = 1;
        r = res = last = 0;
        init();
		action();
	}
	
	inline void add(int x) {
        if (!(mp[x]++)) {
            res++;
        }
    }
	
	inline void sub(int x) {
        if (!(--mp[x])) {
            res--;
        }
    }
	
	inline void update(int opt) {
		if (opt == 1) {
            last++;
        }
		if (ts[last].pos >= l && ts[last].pos <= r) {
			add(ts[last].x);
			sub(a[ts[last].pos]);
		}
		swap(ts[last].x, a[ts[last].pos]);
		if (opt == 0) last--;
	}
	
	inline void init() {
		for (int i = 1; i <= n; i++) read(a[i]);
		for (int i = 1; i <= m; i++) {
			int L, R;
			char opt;
			cin >> opt;
			read(L, R);
			if (opt == 'Q') rs.push_back({L, R, (int)rs.size() + 1, (int)ts.size() - 1});
			else ts.push_back({L, R});
		}
		
		sort(rs.begin(), rs.end(), [&] (const auto &x, const auto &y) {
			if (x.L / len != y.L / len)
				return x.L / len > y.L / len;
			else if (x.R / len != y.R / len)
				return x.R / len > y.R / len;
			else
				return x.tnum > y.tnum;
		});
	}
	
	inline void action() {
		for (auto [L, R, num, tnum] : rs) {
			while (L < l) add(a[--l]);
			while (R > r) add(a[++r]);
			while (L > l) sub(a[l++]);
			while (R < r) sub(a[r--]);
			while (last < tnum) update(1);
			while (last > tnum) update(0);
			ans[num] = res;
		}
	}
	
	inline void print_ans() {
		for (int i = 1; i <= rs.size(); i++)
			cout << ans[i] << '\n';
	}
};

void solve() {
	int n, m;
	read(n, m);
	int len = powl(n, 2.0 / 3.0);
	Cmd<int> t(n, m, len, 1e6);
	t.print_ans();
}

还有些回滚莫队等等一些莫队算法会持续更新...

posted @ 2024-08-12 20:33  grape_king  阅读(35)  评论(2)    收藏  举报