JZOJ 7392. 【2021.11.17NOIP提高组联考】数 (ds)

\(\text{Problem}\)

元素带类型与权值,每次修改权值或类型,求区间每种类型和的 \(k\) 次方和
强制在线

\(\text{Solution}\)

显然简单分块,根据询问需要发现要
维护任意两块之间的答案,每种类型的权值在块中的前缀和
询问就很简单,考虑枚举散块出现的类型先去除其在整块中的贡献再加上散块与整块一起的贡献即可
考虑修改,涉及一个元素,权值和的前缀和只要暴力更新这个元素所在块与其后的所有块即可
任意两块间的答案的更新要枚举覆盖它的连续块,整体考虑这个连续块,也只涉及一个点的修改,可以 \(O(1)\) 更新
设块长为 \(d\)
则询问复杂度为 \(O(md)\),修改为 \(O(m\frac{n^2}{d^2})\)
简单计算出当 \(d = n^{\frac 2 3}\) 是最优
还要那类型的动态离散化,哈希表处理即可
本人代码挂了一个测试点,原因未知

\(\text{Code}\)

#include <cstdio>
#include <cmath>
#include <iostream>
#include <cstring>
#include <tr1/unordered_map>
#define re register
using namespace std;
typedef unsigned int uint;
tr1::unordered_map<uint, int> vis;

const int N = 1e5 + 5;
int n, m, k, ty, c[N], st[N], ed[N], id[N], size, num, buc[N], col[N];
uint v[N], f[41][N], sf[N][41], g[41][41], t[N], sum[N];

inline uint fpow(uint x, int y){uint s = 1; for(; y; y >>= 1, x = x * x) if (y & 1) s = s * x; return s;}
inline uint SF(int c, int l, int r){return sf[c][r] - sf[c][l - 1];}
void prepare()
{
	memset(f, 0, sizeof f), memset(g, 0, sizeof g), memset(sf, 0, sizeof sf);
	num = pow(n, 1.0 / 3);
	for(re int i = 1; i <= num; i++)
	{
		st[i] = ed[i - 1] + 1, ed[i] = (i == num ? n : ed[i - 1] + n / num);
		for(re int j = st[i]; j <= ed[i]; j++) id[j] = i, f[i][c[j]] += v[j];
	}
	for(re int i = 1; i <= size; i++)
		for(re int j = 1; j <= num; j++) sf[i][j] = sf[i][j - 1] + f[j][i];
	for(re int i = 1; i <= num; i++)
	for(re int j = i; j <= num; j++)
	{
		int cnt = 0;
		for(re int l = st[j]; l <= ed[j]; sum[c[l]] += v[l], l++) if (!buc[c[l]]) buc[c[l]] = 1, col[++cnt] = c[l];
		if (i == j) for(re int l = 1; l <= cnt; l++) g[i][i] += fpow(sum[col[l]], k), buc[col[l]] = sum[col[l]] = 0;
		else{
			g[i][j] = g[i][j - 1];
			for(re int l = 1; l <= cnt; l++)
				g[i][j] = g[i][j] - fpow(SF(col[l], i, j - 1), k) + fpow(sum[col[l]] + SF(col[l], i, j - 1), k), buc[col[l]] = sum[col[l]] = 0;
		}
	}
}

inline uint Query(int l, int r)
{
	int x = id[l], y = id[r], cnt = 0; uint res = 0;
	if (x == y || n <= 5000)
	{
		for(re int i = l; i <= r; sum[c[i]] += v[i], i++) if (!buc[c[i]]) buc[c[i]] = 1, col[++cnt] = c[i];
		for(re int i = 1; i <= cnt; i++) res += fpow(sum[col[i]], k), sum[col[i]] = buc[col[i]] = 0;
		return res;
	}
	for(re int i = l; i <= ed[x]; sum[c[i]] += v[i], i++) if (!buc[c[i]]) buc[c[i]] = 1, col[++cnt] = c[i];
	for(re int i = st[y]; i <= r; sum[c[i]] += v[i], i++) if (!buc[c[i]]) buc[c[i]] = 1, col[++cnt] = c[i];
	res = g[x + 1][y - 1];
	for(re int i = 1; i <= cnt; i++)
		res = res - fpow(SF(col[i], x + 1, y - 1), k) + fpow(sum[col[i]] + SF(col[i], x + 1, y - 1), k), buc[col[i]] = sum[col[i]] = 0;
	return res;
}
inline void modify1(int x, uint y)
{
	int p = id[x];
	f[p][c[x]] += y - v[x];
	for(re int i = 1; i <= p; i++)
		for(re int j = p; j <= num; j++) g[i][j] = g[i][j] - fpow(SF(c[x], i, j), k) + fpow(SF(c[x], i, j) - v[x] + y, k);
	for(re int i = p; i <= num; i++) sf[c[x]][i] = sf[c[x]][i - 1] + f[i][c[x]]; v[x] = y;
}
inline void modify2(int x, uint y)
{
	int p = id[x]; uint cl = (vis[y] ? vis[y] : (vis[y] = ++size));
	for(re int i = 1; i <= p; i++)
		for(re int j = p; j <= num; j++)
			g[i][j] = g[i][j] - fpow(SF(c[x], i, j), k) + fpow(SF(c[x], i, j) - v[x], k) - fpow(SF(cl, i, j), k) + fpow(SF(cl, i, j) + v[x], k);
	f[p][c[x]] -= v[x], f[p][cl] += v[x];
	for(re int i = p; i <= num; i++) sf[c[x]][i] = sf[c[x]][i - 1] + f[i][c[x]], sf[cl][i] = sf[cl][i - 1] + f[i][cl];
	c[x] = cl;
}

int main()
{
	freopen("ds.in", "r", stdin), freopen("ds.out", "w", stdout);
	scanf("%d%d%d%d", &n, &m, &k, &ty);
	for(re int i = 1; i <= n; i++) scanf("%u", &v[i]);
	for(re int i = 1; i <= n; c[i] = vis[t[i]], i++) scanf("%u", &t[i]), vis[t[i]] = (vis[t[i]] ? vis[t[i]] : ++size);
	prepare(); char op[5]; uint x, y, lst = 0;
	for(; m; --m)
	{
		scanf("%s%u%u", op, &x, &y);
		if (ty) x ^= lst, y ^= lst;
		if (op[0] == 'Q') printf("%u\n", lst = Query(x, y));
		else if (op[0] == 'C') modify1(x, y);
		else modify2(x, y);
	}
}
原文地址:https://www.cnblogs.com/leiyuanze/p/15577444.html