zoukankan      html  css  js  c++  java
  • 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);
    	}
    }
    
  • 相关阅读:
    CentOS6 配置阿里云 NTP 服务
    使用docker-compose运行nginx容器挂载时遇到的文件/目录问题
    Springboot配置文件参数使用docker-compose实现动态配置
    Dockerfile文件全面详解
    docker 生成mysql镜像启动时自动执行sql
    CentOS无法识别NTFS格式U盘完美解决方案
    网络模型与网络策略
    k8s更换网络插件:从flannel更换成calico
    数据采集实战(四)-- 线性代数习题答案下载
    leedcode 146. LRU 缓存机制(哈希+双向链表)
  • 原文地址:https://www.cnblogs.com/leiyuanze/p/15577444.html
Copyright © 2011-2022 走看看