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);
    	}
    }
    
  • 相关阅读:
    MS CRM 2011 RC中的新特性(4)——活动方面之批量编辑、自定义活动
    最近的一些有关MS CRM 2011的更新
    MS CRM 2011 RC中的新特性(6)——连接
    MS CRM 2011 RC中的新特性(7)—仪表板
    参加MS CRM2011深度培训课程——第一天
    MS CRM 2011插件调试工具
    MS CRM2011实体介绍(四)——目标管理方面的实体
    MS CRM 2011 RC中的新特性(3)——客户服务管理方面
    MS CRM 2011 RC中的新特性(8)—数据管理
    ExtAspNet 登陆
  • 原文地址:https://www.cnblogs.com/leiyuanze/p/15577444.html
Copyright © 2011-2022 走看看