题目链接

题意:\(n\) 个数,每个数都在 \([1,c]\) 中,\(m\) 次询问,每次问在 \([l,r]\) 中有多少个数出现偶数次。强制在线。

\(1 \leq n,m,c \leq 10^5\)

如果不强制在线的话可以想到莫队,关键这个强制在线怎么处理。

很容易想到对原数列进行根号分块,为了方便表示,定义 \(L_i\) 为第 \(i\) 块的左端点,\(R_i\) 为第 \(i\) 块的右端点。

我们记 \(t_{i,j}\) 表示在 \([L_i,n]\) 中 \(j\) 这个数出现了多少次,\(f_{i,j}\) 表示在 \([L_i,R_j]\) 有多少个数出现次数为偶数。

我还是太 naive 了,一看到这个“区间”就想着用区间 dp 的方式进行转移,复杂度爆炸。

事实上,我们可以在求出 \(t\) 的同时求出 \(f\)。枚举起点块 \(i\),定义 \(num\) 记录有多少个数出现了偶数次,一边往后扫一遍更新 \(num\)。

查询区间 \([l,r]\) 的时候,如果 \(l,r\) 在同一块中,直接暴力查找就行了。

如果 \([l,r]\) 不在同一块中,记 \(l'\) 为 \(l\) 所在的块,\(r'\) 为 \(r\) 所在的块,那么我们先将 \(ans\) 赋值为 \(f_{l'+1,r'-1}\),然后对于 \([l,R_{l'}] \cup [L_{r'},r]\) 中所有不同的数 \(x\),分出以下三种情况:

  1. \(x\) 在 \([L_{l'+1},R_{r'-1}]\) 中出现次数为不为零的偶数,但是在 \([l,r]\) 中出现次数为奇数,则表明它被算在了 \(ans\) 中,但实际不符合条件,让 \(ans\) 减一
  2. \(x\) 在 \([L_{l'+1},R_{r'-1}]\) 中出现次数奇数,但是在 \([l,r]\) 中出现次数为偶数,则表明它没有被算在了 \(ans\) 中,但实际符合条件,让 \(ans\) 加一
  3. \(x\) 在 \([L_{l'+1},R_{r'-1}]\) 中没出现过,但是在 \([l,r]\) 中出现次数为偶数,让 \(ans\) 加 \(1\)。
//Coded by tzc_wk
/*
数据不清空,爆零两行泪。
多测不读完,爆零两行泪。
边界不特判,爆零两行泪。
贪心不证明,爆零两行泪。
D P 顺序错,爆零两行泪。
大小少等号,爆零两行泪。
变量不统一,爆零两行泪。
越界不判断,爆零两行泪。
调试不注释,爆零两行泪。
溢出不 l l,爆零两行泪。
*/
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fz(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define foreach(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
#define all(a) a.begin(),a.end()
#define giveup(...) return printf(__VA_ARGS__),0;
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,0x3f,sizeof(a))
#define fillsmall(a) memset(a,0xcf,sizeof(a))
#define mask(a) (1ll<<(a))
#define maskx(a,x) ((a)<<(x))
#define _bit(a,x) (((a)>>(x))&1)
#define _sz(a) ((int)(a).size())
#define filei(a) freopen(a,"r",stdin);
#define fileo(a) freopen(a,"w",stdout);
#define fileio(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
#define eprintf(...) fprintf(stderr,__VA_ARGS__)
#define put(x) putchar(x)
#define eoln put('\n')
#define space put(' ')
#define y1 y_chenxiaoyan_1
#define y0 y_chenxiaoyan_0
typedef pair<int,int> pii;
inline int read(){
int x=0,neg=1;char c=getchar();
while(!isdigit(c)){
if(c=='-') neg=-1;
c=getchar();
}
while(isdigit(c)) x=x*10+c-'0',c=getchar();
return x*neg;
}
inline void print(int x){
if(x<0){
putchar('-');
print(abs(x));
return;
}
if(x<=9) putchar(x+'0');
else{
print(x/10);
putchar(x%10+'0');
}
}
inline int qpow(int x,int e,int _MOD){
int ans=1;
while(e){
if(e&1) ans=ans*x%_MOD;
x=x*x%_MOD;
e>>=1;
}
return ans;
}
const int BLOCK_SZ=320;
int n=read(),c=read(),m=read(),a[100005],cnt[322][100005],sum[322][322];
int blk,L[322],R[322],bel[100005];
int vis[100005];
inline void prework(){
blk=(n-1)/BLOCK_SZ+1;
fz(i,1,blk){
L[i]=(i-1)*BLOCK_SZ+1;
R[i]=min(i*BLOCK_SZ,n);
fz(j,L[i],R[i]){
bel[j]=i;
}
}
fz(i,1,blk){
int num=0;
fill0(vis);
fz(j,L[i],n){
cnt[i][a[j]]++;
if(!vis[a[j]]) vis[a[j]]=1,num++;
if(cnt[i][a[j]]&1) num--;
else num++;
if(bel[j]!=bel[j+1]) sum[i][bel[j]]=num;
}
}
}
int cntt[100005];
inline int query(int l,int r){
if(bel[l]==bel[r]){
int ans=0;
fz(i,l,r) cntt[a[i]]++;
fz(i,l,r){
if(!vis[a[i]]){
if(cntt[a[i]]&1^1) ans++;
vis[a[i]]=1;
}
}
fz(i,l,r) cntt[a[i]]--,vis[a[i]]=0;
return ans;
}
else{
int l0=bel[l],r0=bel[r];
fz(i,l,R[l0]) cntt[a[i]]++;
fz(i,L[r0],r) cntt[a[i]]++;
int ans=sum[l0+1][r0-1];
fz(i,l,R[l0]){
if(!vis[a[i]]){
if((cnt[l0+1][a[i]]-cnt[r0][a[i]])>0){
if(((cntt[a[i]]+cnt[l0+1][a[i]]-cnt[r0][a[i]])&1^1)&&(cnt[l0+1][a[i]]-cnt[r0][a[i]])&1)
ans++;
if(((cntt[a[i]]+cnt[l0+1][a[i]]-cnt[r0][a[i]])&1)&&(cnt[l0+1][a[i]]-cnt[r0][a[i]])&1^1)
ans--;
}
else{
if((cntt[a[i]]&1)^1) ans++;
}
vis[a[i]]=1;
}
}
fz(i,L[r0],r){
if(!vis[a[i]]){
if((cnt[l0+1][a[i]]-cnt[r0][a[i]])>0){
if(((cntt[a[i]]+cnt[l0+1][a[i]]-cnt[r0][a[i]])&1^1)&&(cnt[l0+1][a[i]]-cnt[r0][a[i]])&1)
ans++;
if(((cntt[a[i]]+cnt[l0+1][a[i]]-cnt[r0][a[i]])&1)&&(cnt[l0+1][a[i]]-cnt[r0][a[i]])&1^1)
ans--;
}
else{
if(cntt[a[i]]&1^1) ans++;
}
vis[a[i]]=1;
}
}
fz(i,l,R[l0]) cntt[a[i]]--,vis[a[i]]=0;
fz(i,L[r0],r) cntt[a[i]]--,vis[a[i]]=0;
return ans;
}
}
signed main(){
fz(i,1,n) a[i]=read();
prework();
fill0(vis);
int anss=0;
while(m--){
int l=read(),r=read();
l=(l+anss)%n+1,r=(r+anss)%n+1;
if(l>r) swap(l,r);
anss=query(l,r);
cout<<anss<<endl;
}
return 0;
}

洛谷 P4135 作诗(分块)的更多相关文章

  1. 洛谷P4135 作诗 (分块)

    洛谷P4135 作诗 题目描述 神犇SJY虐完HEOI之后给傻×LYD出了一题: SHY是T国的公主,平时的一大爱好是作诗. 由于时间紧迫,SHY作完诗之后还要虐OI,于是SHY找来一篇长度为N的文章 ...

  2. 洛谷 P4135 作诗 题解

    题面. 之前做过一道很类似的题目 洛谷P4168蒲公英 ,然后看到这题很快就想到了解法,做完这题可以对比一下,真的很像. 题目要求区间内出现次数为正偶数的数字的数量. 数据范围1e5,可以分块. 我们 ...

  3. 洛谷P4135 作诗(不一样的分块)

    题面 给定一个长度为 n n n 的整数序列 A A A ,序列中每个数在 [ 1 , c ] [1,c] [1,c] 范围内.有 m m m 次询问,每次询问查询一个区间 [ l , r ] [l, ...

  4. 洛谷P4135 作诗

    题意:[l,r]之间有多少个数出现了正偶数次.强制在线. 解:第一眼想到莫队,然后发现强制在线...分块吧. 有个很朴素的想法就是蒲公英那题的套路,做每块前缀和的桶. 然后发现这题空间128M,数组大 ...

  5. 洛谷 P4135 作诗

    分块大暴力,跟区间众数基本一样 #pragma GCC optimize(3) #include<cstdio> #include<algorithm> #include< ...

  6. P4135 作诗——分块

    题目:https://www.luogu.org/problemnew/show/P4135 分块大法: 块之间记录答案,每一块记录次数前缀和: 注意每次把桶中需要用到位置赋值就好了: 为什么加了特判 ...

  7. 洛谷P4198 楼房重建 (分块)

    洛谷P4198 楼房重建 题目描述 小A的楼房外有一大片施工工地,工地上有N栋待建的楼房.每天,这片工地上的房子拆了又建.建了又拆.他经常无聊地看着窗外发呆,数自己能够看到多少栋房子. 为了简化问题, ...

  8. 洛谷P3247 [HNOI2016]最小公倍数 [分块,并查集]

    洛谷 思路 显然,为了达到这个最小公倍数,只能走\(a,b\)不是很大的边. 即,当前询问的是\(A,B\),那么我们只能走\(a\leq A,b\leq B\)的边. 然而,为了达到这最小公倍数,又 ...

  9. 洛谷P4135 Ynoi2016 掉进兔子洞 (带权bitset?/bitset优化莫队 模板) 题解

    题面. 看到这道题,我第一反应就是莫队. 我甚至也猜出了把所有询问的三个区间压到一起处理然后分别计算对应询问答案. 但是,这么复杂的贡献用什么东西存?难道要开一个数组 query_appear_tim ...

随机推荐

  1. 无网环境安装docker之--rpm

    总体思路:找一台可以联网的linux,下载docker的RPM依赖包而不进行安装(yum localinstall),将所有依赖的rpm环境打包好,再在无网环境中解压逐一安装(rpm:  --forc ...

  2. 写了10000条Airtest截图脚本总结出来的截图经验,赶紧收藏!

    前言 今天想先给大家分享1个小白用户的Airtest从入门到放弃的故事: 小A是一个自动化的小白,在逛测试论坛的时候,偶然间发现了Airtest这个基于图像识别的UI自动化框架. 出于好奇,小A试用了 ...

  3. Gitlab Burndown Chart

    一.说明 通过调用gitlab api直接获取相应project的所有issues,然后对其进行统计以制作燃尽图 二.方法 1.生成 Personal access token Gitlab > ...

  4. skywalking实现分布式系统链路追踪

    一.背景 随着微服务的越来越流行,我们服务之间的调用关系就显得越来越复杂,我们急需一个APM工具来分析系统中存在的各种性能指标问题以及调用关系.目前主流的APM工具有CAT.Zipkin.Pinpoi ...

  5. 零基础学习STM32之入门学习路线

    可以说就目前的市场需求来看,stm32在单片机领域已经拥有了绝对的地位,51什么的已经过时了也只能拿来打基础了,最后依然会转到stm32来,也正是因为这样stm32的学习者越来越多,其中不难发现绝大部 ...

  6. 零基础学习Linux必会的60个常用命令

    Linux必学的60个命令Linux提供了大量的命令,利用它可以有效地完成大量的工 作,如磁盘操作.文件存取.目录操作.进程管理.文件权限设定等.所以,在Linux系统上工作离不开使用系统提供的命令. ...

  7. 基于Vue的工作流项目模块中,使用动态组件的方式统一呈现不同表单数据的处理方式

    在基于Vue的工作流项目模块中,我们在查看表单明细的时候,需要包含公用表单信息,特定表单信息两部分内容.前者表单数据可以统一呈现,而后者则是不同业务的表单数据不同.为了实现更好的维护性,把它们分开作为 ...

  8. LCA-离线tarjan模板

    /* *算法引入: *树上两点的最近公共祖先; *对于有根树的两个结点u,v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u,v的祖先且x的深度尽可能大; *对于x来说,从u到v的路径一定 ...

  9. ARM 链接配置.lds文件学习<转>

    本文由Jacky原创,来自http://blog.chinaunix.net/u1/58780/showart.php?id=462971 对于.lds文件,它定义了整个程序编译之后的连接过程,决定了 ...

  10. 第36篇-return字节码指令

    方法返回的字节码相关指令如下表所示. 0xac ireturn 从当前方法返回int 0xad lreturn 从当前方法返回long 0xae freturn 从当前方法返回float 0xaf d ...