zoukankan      html  css  js  c++  java
  • bzoj2906 颜色 分块+块大小分析

    题目传送门

    https://lydsy.com/JudgeOnline/problem.php?id=2906

    题解

    如果可以离线的话,那么这个题目就是一个莫队的裸题。

    看上去这个数据范围也还会一个根号算法,所以考虑分块。

    每一次询问,我们需要知道整块的答案。如果单独知道整块看上去不太好搞,所以可以预处理整块到整块的答案。令 (c[i][j][k]) 表示从 (i) 块到 (j)(leq k) 的答案,询问的时候 (ans) 先加上中间整块的 (c) 值,然后枚举小块中的点,每个点都可以统计一次这个颜色在整块和之前统计过的部分的出现次数,然后减掉之前的,加上现在新的,就可以更新答案了。

    考虑 (c[i][j][k]) 应该怎么求。令 (b[i][k]) 表示前 (i) 个块中出现的颜色 (k) 的方案数。前缀和减一下就好了。

    但是如果直接按照 (sqrt n) 分块的话,时空复杂度显然要炸。所以我们需要调整块大小。预处理的时空复杂度显然都是 (O((frac nb) ^ 2 m)),后面的询问的复杂度是 (O(qb))。当 (b = n^{frac 23}) 时最优。


    因此总的时间复杂度为 (O(n^{frac23} m + n^{frac 23} q))

    #include<bits/stdc++.h>
    
    #define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
    #define dbg(...) fprintf(stderr, __VA_ARGS__)
    #define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
    #define fi first
    #define se second
    #define pb push_back
    
    template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
    template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;}
    
    typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
    
    template<typename I> inline void read(I &x) {
    	int f = 0, c;
    	while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
    	x = c & 15;
    	while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
    	f ? x = -x : 0;
    }
    
    const int N = 50000 + 7;
    const int M = 20000 + 7;
    const int B = 40 + 3;
    
    #define bl(x) (((x) - 1) / blo + 1)
    #define st(x) (((x) - 1) * blo + 1)
    #define ed(x) std::min((x) * blo, n)
    
    int n, m, Q, blo;
    int a[N];
    ll sqr[N], c[B][B][M];
    int b[B][M], cnt[M], pp[M];
    
    inline void ycl() {
    	for (int i = 1; i <= n; ++i) sqr[i] = (ll)i * i;
    	for (int i = 1; i <= bl(n); ++i) {
    		for (int j = st(i); j <= ed(i); ++j) ++b[i][a[j]];
    //		for (int j = 1; j <= m; ++j) b[i][j] += b[i][j - 1];
    		for (int j = 1; j <= m; ++j) b[i][j] += b[i - 1][j];//, dbg("b[%d][%d] = %d
    ", i, j, b[i][j]);
    	}
    //	assert(b[bl(n)][m] == n);
    	for (int i = 1; i <= bl(n); ++i)
    		for (int j = i; j <= bl(n); ++j) {
    			for (int k = 1; k <= m; ++k) c[i][j][k] = sqr[b[j][k] - b[i - 1][k]];//, dbg("c[%d][%d][%d] = %d
    ", i, j, k, c[i][j][k]);
    			for (int k = 1; k <= m; ++k) c[i][j][k] += c[i][j][k - 1];
    		}
    }
    
    inline ll qry(int l, int r, int k) {
    	if (k <= 0) return 0;
    	if (bl(l) == bl(r)) {
    		ll ans = 0;
    		for (int i = l; i <= r; ++i) if (a[i] <= k) ++cnt[a[i]], pp[a[i]] = i;
    		for (int i = l; i <= r; ++i) if (a[i] <= k && pp[a[i]] == i) ans += sqr[cnt[a[i]]], cnt[a[i]] = 0;
    		return ans;
    	}
    	ll ans = c[bl(l) + 1][bl(r) - 1][k];
    //	dbg("ans = %lld
    ", ans);
    	for (int i = l; i <= ed(bl(l)); ++i) if (a[i] <= k) ++cnt[a[i]], pp[a[i]] = i;
    	for (int i = st(bl(r)); i <= r; ++i) if (a[i] <= k) ++cnt[a[i]], pp[a[i]] = i;
    	for (int i = l; i <= ed(bl(l)); ++i) if (a[i] <= k && pp[a[i]] == i) {
    		ans += sqr[cnt[a[i]] + b[bl(r) - 1][a[i]] - b[bl(l)][a[i]]];
    		ans -= sqr[b[bl(r) - 1][a[i]] - b[bl(l)][a[i]]];
    		cnt[a[i]] = 0;
    	}
    	for (int i = st(bl(r)); i <= r; ++i) if (a[i] <= k && pp[a[i]] == i) {
    		ans += sqr[cnt[a[i]] + b[bl(r) - 1][a[i]] - b[bl(l)][a[i]]];
    		ans -= sqr[b[bl(r) - 1][a[i]] - b[bl(l)][a[i]]];
    		cnt[a[i]] = 0;
    	}
    	return ans;
    }
    
    inline void work() {
    	ycl();
    	ll la = 0;
    	while (Q--) {
    		int l, r, a, b;
    		read(l), read(r), read(a), read(b);
    		l ^= la, r ^= la, a ^= la, b ^= la;
    		assert(l <= r);
    		assert(r <= n);
    		assert(l >= 1);
    		assert(a <= b);
    		assert(b <= m);
    		assert(a >= 1);
    		printf("%lld
    ", la = qry(l, r, b) - qry(l, r, a - 1));
    	}
    }
    
    inline void init() {
    	read(n), read(m), read(Q);
    	blo = pow(n, 2.0 / 3);
    //	blo = ;
    	for (int i = 1; i <= n; ++i) read(a[i]);
    //	dbg("******* blo = %d
    ", blo);
    }
    
    int main() {
    #ifdef hzhkk
    	freopen("hkk.in", "r", stdin);
    #endif
    	init();
    	work();
    	fclose(stdin), fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    time 模块学习
    day 14 自定义模块,常用模块 time .datetime ,time 模块
    day 13 课后作业
    day 12 课后作业
    day 11课后作业
    树状数组最值
    hdu 1059 Dividing bitset 多重背包
    XVII Open Cup named after E.V. Pankratiev. XXI Ural Championship
    最长公共子序列板/滚动 N^2
    Uva 10635
  • 原文地址:https://www.cnblogs.com/hankeke/p/bzoj2906.html
Copyright © 2011-2022 走看看