bzoj2453 维护队列 & bzoj2120 数颜色 (带修改莫队)
2017-11-26 11:01
316 查看
bzoj2453 维护队列 & bzoj2120 数颜色
原题地址:http://www.lydsy.com/JudgeOnline/problem.php?id=2453
http://www.lydsy.com/JudgeOnline/problem.php?id=2120
题意:
小朋友A有一些弹珠,A喜欢把它们排成队列,从左到右编号为1到N。
小朋友想知道某一段连续弹珠中,不同颜色的弹珠有多少。
A有时候会依据个人喜好,替换队列中某个弹珠的颜色。
数据范围
1 ≤ N ≤ 10000, 1 ≤ M ≤ 10000,小朋友A不会修改超过1000次,所有颜色均用1到10^6的整数表示。
题解:
带修改莫队裸题。
相比不带修多了一维时间(在第几个修改之后)。
块大小n23,块个数n13
排序按照 L所在快,R所在块,时间(在第几个修改之后) 排序。
复杂度证明:
左指针移动:n次*n23的距离=O(n∗n23)= O(n53)
右指针移动:n次 * n23的距离+n13次 * n23的距离= O(n∗n23+n13∗n)= O(n53)
时间指针移动:(n13)2次 * n的距离=O((n13)2∗n)= O(n53)
于是复杂度 O(n53)
代码:
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<cmath> using namespace std; const int N=10000; struct query { int l,r,t,id; }Q ; struct modify { int pos,pre,nxt; }M ; int n,m,col ,st ,ans ,block,ret=0,qs,md,cnt[1000006]; int blo(int x) { return(x-1)/block+1; } bool cmp(const query &A,const query &B) { if(blo(A.l)!=blo(B.l)) return A.l<B.l; else if(blo(A.r)!=blo(B.r)) return A.r<B.r; else return A.t<B.t; } void add(int x) {x=col[x]; if(!cnt[x]) ret++; cnt[x]++;} void erase(int x) {x=col[x]; cnt[x]--; if(cnt[x]==0) ret--;} void change(int tim,int l,int r,int opt) { int pos=M[tim].pos; int pre=M[tim].pre; int now=M[tim].nxt; if(pos>=l&&pos<=r) erase(pos); col[pos]=(opt>0)? now:pre; if(pos>=l&&pos<=r) add(pos); } void moto() { int lf=1; int rg=0; int cur=0; ret=0; for(int i=1;i<=qs;i++) { while(rg<Q[i].r) add(++rg); while(lf>Q[i].l) add(--lf); while(lf<Q[i].l) erase(lf++); while(rg>Q[i].r) erase(rg--); while(cur<Q[i].t) change(++cur,Q[i].l,Q[i].r,1); while(cur>Q[i].t) change(cur--,Q[i].l,Q[i].r,-1); ans[Q[i].id]=ret; } } int main() { scanf("%d%d",&n,&m); block=sqrt(n); for(int i=1;i<=n;i++) {scanf("%d",&col[i]);st[i]=col[i];} qs=0,md=0; for(int i=1;i<=m;i++) { char opt[5]; int x,y; scanf("%s",opt); scanf("%d%d",&x,&y); if(opt[0]=='Q') { Q[++qs].l=x;Q[qs].r=y; Q[qs].t=md; Q[qs].id=qs; } else { M[++md].pos=x; M[md].pre=col[x]; M[md].nxt=y; col[x]=y; } } for(int i=1;i<=n;i++) col[i]=st[i]; sort(Q+1,Q+qs+1,cmp); moto(); for(int i=1;i<=qs;i++) printf("%d\n",ans[i]); return 0; }
相关文章推荐
- BZOJ 2120 数颜色&2453 维护队列 [带修改的莫队算法]【学习笔记】
- Bzoj 2120: 数颜色 && 2453: 维护队列 莫队,分块,bitset
- [BZOJ2120] 数颜色 && [bzoj2453] 维护队列(莫队 || 分块)
- BZOJ 2120: 数颜色/BZOJ 2453: 维护队列 带修改莫队
- 【BZOJ】【2120】数颜色 & 【2453】维护队列
- BZOJ 2120: 数颜色&&2453: 维护队列【双倍经验】
- 【BZOJ-2453&2120】维护队列&数颜色 分块 + 带修莫队算法
- BZOJ 2453: 维护队列&&BZOJ 2120 数颜色 分块
- [树状数组套权值线段树 || 分块] BZOJ 2120 数颜色 & BZOJ 2453 维护队列
- Bzoj 2453: 维护队列 && Bzoj 2120: 数颜色 分块,bitset
- BZOJ2453: 维护队列&2120: 数颜色
- BZOJ 2120: 数颜色 && 2453: 维护队列 【带修莫队版题【也可以学黄学长分块
- 【BZOJ】2453: 维护队列【BZOJ】2120: 数颜色 二分+分块(暴力能A)
- BZOJ.2453.维护队列([模板]带修改莫队)
- 【bzoj 2120】维护队列【bzoj 2453】数颜色 双倍经验!!!
- BZOJ[2120]数颜色/BZOJ[2453]维护队列 分块
- 【BZOJ2453】维护队列/【BZOJ2120】数颜色 分块
- [BZOJ 2453]维护队列:带修改莫队
- 【bzoj2453】维护队列/【bzoj2120】数颜色 分块+二分
- 【bzoj 2120】维护队列【bzoj 2453】数颜色 双倍经验!!!