• 【bzoj2906】颜色 分块


    题目描述

    给定一个长度为N的颜色序列C,对于该序列中的任意一个元素Ci,都有1<=Ci<=M。对于一种颜色ColorK来说,区间[L,R]内的权值定义为这种颜色在该区间中出现的次数的平方,即区间[L,R]内中满足Ci=ColorK的元素个数的平方。接下来给出Q个询问,询问区间[L,R]内颜色[a,b]的权值总和。

    输入

    第1行三个整数N,M,Q。分别代表序列长度,颜色总数和询问总数。
    第2行N个整数,代表序列Ci。
    第3行到第Q+2行,每行4个整数l,r,a,b。记上一次计算出的答案为Lans。那么实际的l,r,a,b为给出的l,r,a,b xor上Lans。第一个询问的时候Lans=0。

    输出

    总共Q行,对于每一个询问,输出权值总和

    样例输入

    4 2 3
    1 1 2 2 
    1 4 1 2
    10 11 9 10
    3 0 0 0

    样例输出

    8
    2
    0


    题解

    分块

    这种二叉数据结构维护不了,又强制在线的,大概就是分块了。

    维护 $f[i][j][k]$ 表示从第 $i$ 块到第 $j$ 块,权值在 $[1,k]$ 之间的个数平方和。为了方便处理零碎部分,还要维护 $c[i][j][k]$ 表示从第 $i$ 块到第 $j$ 块,权值为 $k$ 的个数。

    对于询问转化为权值的前缀相减处理,整块部分直接拿出答案,零碎部分暴力枚举,算出对平方和的贡献。

    设块的大小为 $si$ ,则预处理时间复杂度为 $O(n·(frac n{si})^2)$ ,询问时间复杂度为 $O(n·si)$ 。根据均值不等式,当 $si=n^{frac 23}$ 时复杂度最优,为 $O(n^{frac 53})$ 

    #include <cstdio>
    #include <cstring>
    typedef unsigned int ui;
    ui a[50010] , f[40][40][20010] , c[40][40][20010] , sum[20010] , cnt[20010];
    int main()
    {
    	ui n , m , q , si = 1 , i , j , k , l , r , x , y , bl , br , ans = 0;
    	scanf("%u%u%u" , &n , &m , &q);
    	for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &a[i]);
    	while(si * si * si < n * n) si ++ ;
    	for(i = 1 ; i <= (n - 1) / si + 1 ; i ++ )
    	{
    		for(j = i ; j <= (n - 1) / si + 1 ; j ++ )
    		{
    			for(k = (j - 1) * si + 1 ; k <= j * si && k <= n ; k ++ ) sum[a[k]] += cnt[a[k]] << 1 | 1 , cnt[a[k]] ++ ;
    			for(k = 1 ; k <= m ; k ++ ) c[i][j][k] = cnt[k] , f[i][j][k] = sum[k] + f[i][j][k - 1];
    		}
    		memset(sum , 0 , sizeof(sum));
    		memset(cnt , 0 , sizeof(cnt));
    	}
    	while(q -- )
    	{
    		scanf("%u%u%u%u" , &l , &r , &x , &y) , l ^= ans , r ^= ans , x ^= ans , y ^= ans;
    		bl = (l - 1) / si + 1 , br = (r - 1) / si + 1 , ans = f[bl + 1][br - 1][y] - f[bl + 1][br - 1][x - 1];
    		if(bl == br)
    		{
    			for(i = l ; i <= r ; i ++ ) if(a[i] >= x && a[i] <= y) ans += cnt[a[i]] << 1 | 1 , cnt[a[i]] ++ ;
    			for(i = l ; i <= r ; i ++ ) if(a[i] >= x && a[i] <= y) cnt[a[i]] -- ;
    		}
    		else
    		{
    			for(i = l ; i <= bl * si ; i ++ ) if(a[i] >= x && a[i] <= y) ans += (c[bl + 1][br - 1][a[i]] + cnt[a[i]]) << 1 | 1 , cnt[a[i]] ++ ;
    			for(i = r ; i > (br - 1) * si ; i -- ) if(a[i] >= x && a[i] <= y) ans += (c[bl + 1][br - 1][a[i]] + cnt[a[i]]) << 1 | 1 , cnt[a[i]] ++ ;
    			for(i = l ; i <= bl * si ; i ++ ) if(a[i] >= x && a[i] <= y) cnt[a[i]] -- ;
    			for(i = r ; i > (br - 1) * si ; i -- ) if(a[i] >= x && a[i] <= y) cnt[a[i]] -- ;
    		}
    		printf("%u
    " , ans);
    	}
    	return 0;
    }
    

     

  • 相关阅读:
    列表常用方法及演示
    print >> 重定向
    简单字符串过滤练习
    None,Python 的 Null 对象,布尔值
    Time模块简单学习
    str()与repr(),input()与raw_input()
    布尔数,__nonzero__()
    字符串内建函数
    标准类型内建函数
    客户端precommit hook参数
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/8611440.html
Copyright © 2020-2023  润新知