bzoj 2453 : 维护队列 带修莫队
2017-03-11 20:46
211 查看
2453: 维护队列
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 952 Solved: 432
[Submit][Status][Discuss]
Description
你小时候玩过弹珠吗?小朋友A有一些弹珠,A喜欢把它们排成队列,从左到右编号为1到N。为了整个队列鲜艳美观,小朋友想知道某一段连续弹珠中,不同颜色的弹珠有多少。当然,A有时候会依据个人喜好,替换队列中某个弹珠的颜色。但是A还没有学过编程,且觉得头脑风暴太浪费脑力了,所以向你来寻求帮助。
Input
输入文件第一行包含两个整数N和M。第二行N个整数,表示初始队列中弹珠的颜色。
接下来M行,每行的形式为“Q L R”或“R x c”,“Q L R”表示A想知道从队列第L个弹珠到第R个弹珠中,一共有多少不同颜色的弹珠,“R x c”表示A把x位置上的弹珠换成了c颜色。
Output
对于每个Q操作,输出一行表示询问结果。Sample Input
2 31 2
Q 1 2
R 1 2
Q 1 2
Sample Output
21
HINT
对于100%的数据,有1 ≤ N ≤ 10000, 1 ≤ M ≤ 10000,小朋友A不会修改超过1000次,所有颜色均用1到10^6的整数表示。Source
2011福建集训把询问和修改分开排序,修改按时间排,询问以左端点所在块为第一关键字,右端点所在块为第二关键字,时间为第三关键字排序。
维护左右时间三个指针,不断修改还原。
块大小为$n^{\frac{2}{3}}$。
左指针每个询问走$n^{\frac{2}{3}}$。
右指针同理,不过要多上每次总从左走到右的复杂度,总共$n\times n^{\frac{2}{3}}+n\times n^{\frac{1}{3}}$。
时间指针每次左右端点所在块变化重新开始走,一共$n^{\frac{2}{3}}$个不同的左右块匹配数,复杂度$n\times n^{\frac{2}{3}}$.
好像块开100比较快。
(写莫队时一定要先把lr往两边移,再向中间移)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define d 100 #define N 10005 using namespace std; int n,m; int c ; struct node { int l,r,t,pr; node(){l=r=t=0;} }q ,g ; int cnt1,cnt2; bool cmp1(const node &aa,const node &bb) { return aa.t<bb.t; } int be1 ,be2 ; bool cmp2(const node &aa,const node &bb) { if(be1[aa.l]==be1[bb.l]) { if(be2[aa.r]==be2[bb.r])return aa.t<bb.t; return aa.r<bb.r; } return aa.l<bb.l; } int ans ; int now[N*100],cnt; void solve() { int p1,p2,p; memset(now,0,sizeof(now)); now[c[1]]=1;cnt=1;g[cnt1+1].t=10005; p=p1=1; p2=0; for(int i=1;i<=cnt2;i++) { while(g[p2+1].t<q[i].t) { p2++; int tmp=c[g[p2].l]; g[p2].pr=tmp; c[g[p2].l]=g[p2].r; if(g[p2].l<=p&&g[p2].l>=p1) { now[tmp]--; if(!now[tmp])cnt--; now[g[p2].r]++; if(now[g[p2].r]==1)cnt++; } } while(g[p2].t>q[i].t) { c[g[p2].l]=g[p2].pr; if(g[p2].l<=p&&g[p2].l>=p1) { now[g[p2].r]--; if(!now[g[p2].r])cnt--; now[g[p2].pr]++; if(now[g[p2].pr]==1)cnt++; } p2--; } while(p<q[i].r) { p++;now[c[p]]++; if(now[c[p]]==1)cnt++; } while(p>q[i].r) { now[c[p]]--;if(!now[c[p]])cnt--; p--; } while(p1<q[i].l) { now[c[p1]]--;if(!now[c[p1]])cnt--; p1++; } while(p1>q[i].l) { p1--;now[c[p1]]++; if(now[c[p1]]==1)cnt++; } ans[q[i].t]=cnt; } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%d",&c[i]); for(int i=1;i<=n;i++) { be1[i]=be2[i]=(i-1)/d+1; } memset(ans,-1,sizeof(ans)); char s[2]; for(int i=1;i<=m;i++) { scanf("%s",s); if(s[0]=='R') { cnt1++; scanf("%d%d",&g[cnt1].l,&g[cnt1].r); g[cnt1].t=i; } else { cnt2++; scanf("%d%d",&q[cnt2].l,&q[cnt2].r); q[cnt2].t=i; } } sort(q+1,q+cnt2+1,cmp2); sort(g+1,g+cnt1+1,cmp1); solve(); for(int i=1;i<=m;i++) { if(ans[i]!=-1)printf("%d\n",ans[i]); } return 0; }
相关文章推荐
- [BZOJ 2453]维护队列:带修改莫队
- Bzoj 2120: 数颜色 && 2453: 维护队列 莫队,分块,bitset
- [BZOJ2120] 数颜色 && [bzoj2453] 维护队列(莫队 || 分块)
- bzoj2453 维护队列 & bzoj2120 数颜色 (带修改莫队)
- BZOJ 2120: 数颜色/BZOJ 2453: 维护队列 带修改莫队
- [BZOJ2453][维护队列][莫队]
- BZOJ.2453.维护队列([模板]带修改莫队)
- BZOJ 2120 数颜色&2453 维护队列 [带修改的莫队算法]【学习笔记】
- [树状数组套权值线段树 || 分块] BZOJ 2120 数颜色 & BZOJ 2453 维护队列
- BZOJ2453 维护队列 解题报告【数据结构】【分块】
- bzoj 2453: 维护队列
- 【bzoj2453】 维护队列
- [BZOJ2453]维护队列|分块
- Bzoj 2453: 维护队列 && Bzoj 2120: 数颜色 分块,bitset
- 【BZOJ】【2120】数颜色 & 【2453】维护队列
- BZOJ2453: 维护队列
- BZOJ2453维护队列&&BZOJ2120数颜色
- bzoj 2453: 维护队列
- BZOJ 2120: 数颜色 && 2453: 维护队列 【带修莫队版题【也可以学黄学长分块
- [BZOJ2453]维护队列(分块)