zoukankan      html  css  js  c++  java
  • 【题解】 作诗 序列分块 Luogu4135

    Legend

    给定长度为 (n) 的序列 (a_i),区间在线询问 (m) 次出现次数为偶数的数字个数(0 次不算)。

    强制在线。(1 le n ,a_i,m le 10^5)

    Editorial

    好像我的做法比较阴间。

    考虑分块预处理 (val_{i,j}) 表示第 (i) 个块到第 (j) 个块的答案。

    如何处理散块?预处理 (back_{i,v}) 表示第 (i) 个块及以后数字 (v) 从左到右第一次出现的位置。

    (front_{i,v}) 表示第 (i) 个块及以后数字 (v) 从右到左第一次出现的位置。

    再记录一下 (where_i) 每一个位置上的数字是这个数字从左到右第几个。

    这样通过查询块内最靠左/右的数字,用 (where) 作差,就可以判断出来整块内的数字出现的是偶数还是奇数次了。散块就暴力更新就行了。

    复杂度 (O(nsqrt{n}))

    然而在写这篇题解的时候发现好像可以直接前缀和求出奇偶性(

    Code

    #include <bits/stdc++.h>
    
    const int MX = 1e5 + 7;
    const int SIZE = 400;
    
    int read(){
    	char k = getchar(); int x = 0;
    	while(k < '0' || k > '9') k = getchar();
    	while(k >= '0' && k <= '9') x = x * 10 + k - '0' ,k = getchar();
    	return x;
    }
    
    int a[MX] ,buc[MX];
    int VAL[433][433];
    int occb[433][MX];
    int occf[433][MX];
    // occb[i][j] 表示在块 i 及以后 j 第一次出现的位置
    // occf 则是表示之前最后一次出现的位置
    int begin[MX] ,end[MX] ,block[MX] ,where[MX];
    
    std::vector<int> app[MX];
    
    int Query(int l ,int r){
    	int ans = 0;
    	if(block[r] - block[l] <= 1){
    		for(int i = l ; i <= r ; ++i){
    			buc[a[i]] += 1;
    			if((buc[a[i]] & 1) == 0) ++ans;
    			else if(buc[a[i]] != 1) --ans;
    		}
    		for(int i = l ; i <= r ; ++i) buc[a[i]] = 0;
    		return ans;
    	}
    	ans = VAL[block[l] + 1][block[r] - 1];
    	for(int i = end[block[l]] ; i >= l ; --i){
    		if(buc[a[i]]){
    			++buc[a[i]];
    			if(buc[a[i]] & 1) --ans;
    			else ++ans;
    		}
    		else{
    			int now = where[occf[block[r] - 1][a[i]]] - where[i];
    			buc[a[i]] = now + 1;
    			if((buc[a[i]] & 1) == 0) ++ans;
    			else if(buc[a[i]] != 1) --ans;
    		}
    	}
    	for(int i = begin[block[r]] ; i <= r ; ++i){
    		if(buc[a[i]]){
    			++buc[a[i]];
    			if(buc[a[i]] & 1) --ans;
    			else ++ans;
    		}
    		else{
    			int now = where[i] - where[occb[block[l] + 1][a[i]]];
    			buc[a[i]] = now + 1;
    			if((buc[a[i]] & 1) == 0) ++ans;
    			else if(buc[a[i]] != 1) --ans;
    		}
    	}
    	for(int i = l ; i <= end[block[l]] ; ++i) buc[a[i]] = 0;
    	for(int i = begin[block[r]] ; i <= r ; ++i) buc[a[i]] = 0;
    	return ans;
    }
    
    int main(){
    	int n = read() ,c = read() ,m = read();
    	for(int i = 1 ; i <= n ; ++i){
    		a[i] = read();
    		where[i] = app[a[i]].size();
    		app[a[i]].push_back(i);
    		// printf("where[%d] = %d
    " ,i ,where[i]);
    	}
    	for(int i = 0 ,bl = 0 ; i <= n ; ++i){
    		block[i] = bl;
    		if(i % SIZE == 0 || i == n){
    			end[bl] = i;
    			begin[++bl] = i + 1;
    		}
    	}
    
    	memset(occb ,0x3f ,sizeof occb);
    	memset(occf ,0x3f ,sizeof occf);
    	for(int i = n ; i ; --i){
    		if(i == end[block[i]]){
    			for(int j = 0 ; j <= c ; ++j){
    				occb[block[i]][j] = occb[block[i] + 1][j];
    			}
    		}
    		occb[block[i]][a[i]] = i;
    	}
    	for(int i = 1 ; i <= n ; ++i){
    		if(i == begin[block[i]]){
    			for(int j = 0 ; j <= c ; ++j){
    				occf[block[i]][j] = occf[block[i] - 1][j];
    			}
    		}
    		occf[block[i]][a[i]] = i;
    	}
    
    	for(int i = 1 ; i <= n ; i += SIZE){
    		int ans = 0;
    		for(int j = i ; j <= n ; ++j){
    			buc[a[j]] += 1;
    			if((buc[a[j]] & 1) == 0){
    				++ans;
    			}
    			else if(buc[a[j]] != 1) --ans;
    			VAL[block[i]][block[j]] = ans;
    		}
    		for(int j = i ; j <= n ; ++j) buc[a[j]] = 0;
    	}
    	int Online = 1 ,la = 0;
    	while(m--){
    		int l = read() ,r = read();
    		if(Online){
    			l = (l + la) % n + 1;
    			r = (r + la) % n + 1;
    			if(l > r) std::swap(l ,r);
    		}
    		printf("%d
    " ,la = Query(l ,r));
    	}
    }
    
  • 相关阅读:
    牛客 Wannafly 挑战赛26D 禁书目录 排列组合 概率期望
    UOJ#269. 【清华集训2016】如何优雅地求和
    斯特林数 学习笔记
    AtCoder Grand Contest 006 (AGC006) C
    Codeforces 1045D Interstellar battle 概率期望
    Codeforces 1045A Last chance 网络流,线段树,线段树优化建图
    Codeforces 1053C Putting Boxes Together 树状数组
    Codeforces 109D String Transformation 字符串 哈希 KMP
    AtCoder Grand Contest 1~10 做题小记
    AtCoder Grand Contest 002 (AGC002) F
  • 原文地址:https://www.cnblogs.com/imakf/p/13771298.html
Copyright © 2011-2022 走看看