你小时候玩过弹珠吗?
小朋友A有一些弹珠,A喜欢把它们排成队列,从左到右编号为1到N。为了整个队列鲜艳美观,小朋友想知道某一段连续弹珠中,不同颜色的弹珠有多少。当然,A有时候会依据个人喜好,替换队列中某个弹珠的颜色。但是A还没有学过编程,且觉得头脑风暴太浪费脑力了,所以向你来寻求帮助。
对于100%的数据,有1 ≤ N ≤ 10000, 1 ≤ M ≤ 10000,小朋友A不会修改超过1000次,所有颜色均用1到10^6的整数表示。
2011福建集训
细节决定成败啊,改变一个语句就有可能从TLE 转变为AC啊。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define N 10003 using namespace std; int n,m,t,cnt,s; int point[1000003],next[N],pre[N]; int a[N],pos[N]; void work(int x) { int l=(x-1)*cnt+1; int r=min(cnt*x,n); for (int i=l;i<=r;i++) next[i]=pre[i]; sort(next+l,next+r+1); } void change(int x,int v) { for(int i=1;i<=n;i++) point[a[i]]=0; a[x]=v; for (int i=1;i<=n;i++) { int t=pre[i]; pre[i]=point[a[i]]; if (t!=pre[i]) work(pos[i]); point[a[i]]=i; } } int ask(int x,int y) { int ans=0; if (pos[x]==pos[y]) { for (int i=x;i<=y;i++) if (pre[i]<x) ans++; } else { for (int i=x;i<=pos[x]*cnt;i++) if (pre[i]<x) ans++; for (int i=(pos[y]-1)*cnt+1;i<=y;i++) if (pre[i]<x) ans++; for (int i=pos[x]+1;i<=pos[y]-1;i++) { int l=(i-1)*cnt+1; int r=min(i*cnt,n); int t=lower_bound(next+l,next+r+1,x)-next; t-=(l-1); ans+=t-1; } } return ans; } int main() { freopen("a.in","r",stdin); freopen("my.out","w",stdout); scanf("%d%d",&n,&m); cnt=sqrt(n); for (int i=1;i<=n;i++) { scanf("%d",&a[i]); pos[i]=(i-1)/cnt+1; } for (int i=1;i<=n;i++) pre[i]=point[a[i]],point[a[i]]=i; if (n%cnt) s=n/cnt+1; else s=n/cnt; for (int i=1;i<=s;i++) work(i); for (int i=1;i<=m;i++) { char c[10]; int x,y; scanf("%s%d%d",c,&x,&y); if (c[0]=='R') change(x,y); else printf("%d\n",ask(x,y)); } }