算法复习——带修改莫队(bzoj2453)
题目:
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 3
1 2
Q 1 2
R 1 2
Q 1 2
Sample Output
2
1
1
HINT
对于100%的数据,有1 ≤ N ≤ 10000, 1 ≤ M ≤ 10000,小朋友A不会修改超过1000次,所有颜色均用1到10^6的整数表示。
Source
题解:
带修改莫队就是莫队原有排序基础上加个第三关键字:时间,注意排序的顺序都是以所在块为顺序另外利用判断是否在指针内的数组visit[i]结合一个巧妙的change和update操作,另外注意分块的大小为n的2/3次方.
具体见http://blog.csdn.net/doyouseeman/article/details/51869932
代码:
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<ctime> #include<cctype> #include<cstring> #include<string> #include<algorithm> using namespace std; const int N=1e4+5; const int M=1e6+5; inline int R() { char c;int f=0; for(c=getchar();c<'0'||c>'9';c=getchar()); for(;c<='9'&&c>='0';c=getchar()) f=(f<<3)+(f<<1)+c-'0'; return f; } struct node { int l,r,x,id; }ask[N]; struct node2 { int po,va,pre; }modi[N]; int s,n,m,cnt[M],last[N],tots,tota,totm,num[N],id[N],head,tail,now,ans,anss[N]; bool visit[N]; inline bool cmp(node a,node b) { return (id[a.l]<id[b.l])||(id[a.l]==id[b.l]&&id[a.r]<id[b.r])||(id[a.l]==id[b.l]&&id[a.r]==id[b.r]&&a.x<b.x); } inline void update(int pos) { if(visit[pos]) { cnt[num[pos]]--; if(!cnt[num[pos]]) ans--; } else { cnt[num[pos]]++; if(cnt[num[pos]]==1) ans++; } visit[pos]^=1; } inline void change(int pos,int val) { if(visit[pos]) { update(pos); num[pos]=val; update(pos); } else num[pos]=val; } int main() { n=R(),m=R();s=pow(n,2.0/3.0); for(int i=1;i<=n;i++) num[i]=R(),last[i]=num[i]; for(int i=1;i<=n;i++) id[i]=i/s+1;int a,b;char t[5]; for(int i=1;i<=m;i++) { scanf("%s",t); if(t[0]=='Q') ask[++tota].l=R(),ask[tota].r=R(),ask[tota].x=totm,ask[tota].id=tota; else modi[++totm].po=R(),modi[totm].va=R(),modi[totm].pre=last[modi[totm].po],last[modi[totm].po]=modi[totm].va; } sort(ask+1,ask+tota+1,cmp);head=1; for(int i=1;i<=tota;i++) { if(ask[i].x>now) for(int j=now+1;j<=ask[i].x;j++) change(modi[j].po,modi[j].va); else for(int j=now;j>=ask[i].x+1;j--) change(modi[j].po,modi[j].pre); if(head<ask[i].l) for(int j=head;j<=ask[i].l-1;j++) update(j); else for(int j=ask[i].l;j<=head-1;j++) update(j); if(tail>ask[i].r) for(int j=ask[i].r+1;j<=tail;j++) update(j); else for(int j=tail+1;j<=ask[i].r;j++) update(j); head=ask[i].l,tail=ask[i].r,now=ask[i].x,anss[ask[i].id]=ans; } for(int i=1;i<=tota;i++) printf("%d\n",anss[i]); return 0; }