CF877F Ann and Books (分类统计贡献+普通莫队)

CF877F Ann and Books

题意:
商店里有 \(n\) 本书,每本书中有 \(a_i\)\(t_i=1/2\) 类问题。

\(m\) 次询问,每次询问给出一个区间,求有多少个符合下列条件的区间:

  • 这个区间是给出区间的子区间
  • 这个区间的所有书中第 \(1\) 类问题比第 \(2\) 类问题多 \(k\) 个,其中 \(k\) 在所有询问中相同。

抽象一下,也就是求 \([L, R]\) 内有多少个子区间 \([l, r]\) 满足

\[\sum_l^r a[1][i] = \sum_l^r a[2][i] + k \]

\[s[1][r] - s[1][l - 1] = s[2][r] - s[2][l - 1] + k \]

\[s[1][r] - s[2][r] = s[1][l - 1] - s[2][l - 1] + k \]

\(v[i] = s[1][i] - s[2][i]\),将原问题转化为 \([L - 1, R]\) 内多少对 \((i, j)\) 满足

  • \(i < j\)
  • \(v[i] + k = v[j]\)

用莫队维护。
如果在现有区间左侧加入一个数 \(x\),则 \(x\) 只能作为区间左端点,答案加上当前的 \(cnt[x + k]\),删除同理。
如果在现有区间右侧加入一个数 \(x\),则 \(x\) 只能作为区间右端点,答案加上当前的 \(cnt[x - k]\),删除同理。
如果 \(k = 0\),由于自己和自己不能产生贡献,需考虑更新答案和更新 \(cnt\) 的顺序。
离散化的时候注意把 \(v - k\)\(v + k\) 也放进去。

#include<bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i <= (b); ++ i)
#define per(i, a, b) for(int i = (a); i >= (b); -- i)
#define pb emplace_back
#define All(X) X.begin(), X.end()
using namespace std;
using ll = long long;
constexpr int N = 1e5 + 5, B = 300;

#define c(x) ((x) / B) 

struct Node {
	int l, r, id;
	bool operator < (const Node &x) {
		if(c(l) != c(x.l)) return c(l) < c(x.l);
		if(c(l) & 1) return c(r) < c(x.r);
		return c(r) > c(x.r);
	}
} q[N];

ll n, m, k, t[N], v[N], lv[N], rv[N], b[N * 3], cnt[N * 3], idx;
ll res, ans[N];

void add(int x, int y) {
	res += cnt[y], ++ cnt[x];	// 先加上贡献,再更新数值,防止 x = y,del同理
}

void del(int x, int y) {
	-- cnt[x], res -= cnt[y];
}

int main() {
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	cin >> n >> k;
	rep(i, 1, n) cin >> t[i];
	rep(i, 1, n) {
		cin >> v[i];
		v[i] = v[i - 1] + (t[i] == 1 ? 1 : -1) * v[i];
	} 
	rep(i, 0, n) {
		b[++ idx] = v[i];
		b[++ idx] = v[i] - k;
		b[++ idx] = v[i] + k;
	}
	sort(b + 1, b + idx + 1);
	int tot = unique(b + 1, b + idx + 1) - b - 1;
	rep(i, 0, n) {
		lv[i] = lower_bound(b + 1, b + tot + 1, v[i] - k) - b;
		rv[i] = lower_bound(b + 1, b + tot + 1, v[i] + k) - b;
		v[i] = lower_bound(b + 1, b + tot + 1, v[i]) - b;
	}
	cin >> m;
	rep(i, 1, m) cin >> q[i].l >> q[i].r, q[i].id = i;
	sort(q + 1, q + m + 1);
	
	int l = 0, r = -1;
	rep(i, 1, m) {
		auto[L, R, id] = q[i];
		-- L;
		while(l < L) del(v[l], rv[l]), ++ l;
		while(l > L) -- l, add(v[l], rv[l]);
		while(r < R) ++ r, add(v[r], lv[r]);
		while(r > R) del(v[r], lv[r]), -- r;
		ans[id] = res;
	}
	rep(i, 1, m) cout << ans[i] << '\n';
	return 0;
}
posted @ 2024-02-04 01:57  Lu_xZ  阅读(4)  评论(0编辑  收藏  举报