BZOJ 2453: 维护队列 分块 二分

来源:互联网 发布:知君本无邪 编辑:程序博客网 时间:2024/05/17 06:35

2453: 维护队列

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1257  Solved: 583
[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 3
1 2
Q 1 2
R 1 2
Q 1 2

Sample Output

2
1

HINT

对于100%的数据,有1 ≤ N ≤ 10000, 1 ≤ M ≤ 10000,小朋友A不会修改超过1000次,所有颜色均用1到10^6的整数表示。


这种东西的套路都是维护一个单项指针,指向前一个和它颜色相同的

这里就是只要该点的指针在区间外面就说明它是这个区间里第一个该颜色,ans++

然后利用这个性质怎么搞呢

分块 (太巨了/太久没写了。。。)

每个块排序 再二分就好了

和教主的魔法那题差不多了

然后对修改怎么搞呢

最开始写了个双向链表,然后越写越GG

最后无奈去看了hzwer发现思想江化了,因为修改次数小,直接暴力O(n)重构就好了。。。


#include<cmath>#include<ctime>#include<cstdio>#include<cstring>#include<cstdlib>#include<iostream>#include<algorithm>#include<iomanip>#include<vector>#include<string>#include<bitset>#include<queue>#include<map>#include<set>using namespace std;typedef long long ll;inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch<='9'&&ch>='0'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}void print(int x){if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar(x%10+'0');}const int N=10100,C=1000100;int n,m;int pre[N],b[N];int col[N],last[C];int block,bel[N];inline void reset(int x){for(int i=(x-1)*block+1;i<=min(block*x,n);++i)b[i]=pre[i];sort(b+(x-1)*block+1,b+1+min(block*x,n));}void modify(int x,int y){register int i,j;for(i=1;i<=n;++i)last[col[i]]=0;col[x]=y;for(i=1;i<=n;++i){j=pre[i];pre[i]=last[col[i]];if(j^pre[i])reset(bel[i]);last[col[i]]=i;}}inline int getres(int i,int x){int l=(i-1)*block+1,r=min(i*block,n),mid,res=l-1;while(l<=r){mid=(l+r)>>1;b[mid]<x ? (l=mid+1,res=mid) : r=mid-1;}return res-(i-1)*block;}int query(int x,int y){register int i,res=0;if(bel[x]==bel[y]){for(i=x;i<=y;++i)res+=(pre[i]<x);return res;}for(i=x;i<=bel[x]*block;++i)res+=(pre[i]<x);for(i=(bel[y]-1)*block+1;i<=y;++i)res+=(pre[i]<x);for(i=bel[x]+1;i<bel[y];++i)res+=getres(i,x);return res;}int main(){n=read();int Q=read();register int i,x,y;for(i=1;i<=n;++i)col[i]=read();block=sqrt(n);for(i=1;i<=n;++i)bel[i]=(i-1)/block+1;m=bel[n];for(i=1;i<=n;++i){pre[i]=last[col[i]];last[col[i]]=i;}for(i=1;i<=m;++i)reset(i);char opt[2];while(Q--){scanf("%s",opt);x=read();y=read();if(opt[0]=='Q'){print(query(x,y));puts("");}else modify(x,y);}return 0;}/*2 31 2Q 1 2R 1 2Q 1 221*/

原创粉丝点击