标签:说明 last www print 查询 define int 记录 math
https://www.luogu.org/problemnew/show/1903
用pre[i]数组记录上一次和当前i同色的位置
查询[l,r],若pre[i]<r,则说明在[l,i)区间内没用和i同色的,则++ans
于是就可以大胆地分块
对于每一块按照pre[i]排序,再进行二分了
复杂度O(qsqrt(n)log(n)).
#include<stdio.h>
#include<math.h>
#include<algorithm>
#define FOR(i,s,t) for(register int i=s;i<=t;++i)
using std::sort;
using std::lower_bound;
const int N=10011;
const int M=1000011;
inline int min(int a,int b){
return a<b?a:b;
}
int n,q,m,blo;
int c[N],pos[N],pre[N],b[N],last[M];
inline int find(int x,int v){
int l=(x-1)*blo+1,r=min(x*blo,n);
return lower_bound(pre+l,pre+r+1,v)-pre-l;
}
inline void reset(int x){
int l=(x-1)*blo+1,r=min(x*blo,n);
FOR(i,l,r)pre[i]=b[i];
sort(pre+l,pre+r+1);
}
inline void build(){
FOR(i,1,n){
b[i]=last[c[i]];
last[c[i]]=i;
pos[i]=(i-1)/blo+1;
}
FOR(i,1,m)reset(i);
}
inline int ask(int l,int r){
int ans=0;
if(pos[l]==pos[r]){
FOR(i,l,r)if(b[i]<l)++ans;
return ans;
}
for(register int i=l;i<=blo*pos[l];++i)if(b[i]<l)++ans;
for(register int i=blo*(pos[r]-1)+1;i<=r;++i)if(b[i]<l)++ans;
for(register int i=pos[l]+1;i<pos[r];++i)ans+=find(i,l);
return ans;
}
inline void change(int x,int v){
FOR(i,1,n)last[c[i]]=0;
c[x]=v;
FOR(i,1,n){
int t=b[i];
b[i]=last[c[i]];
if(t!=b[i])reset(pos[i]);
last[c[i]]=i;
}
}
int main(){
scanf("%d%d",&n,&q);
FOR(i,1,n)scanf("%d",c+i);
blo=int(sqrt(n));
m=n%blo?(n/blo+1):n/blo;
build();
char ch[5];int x,y;
while(q--){
scanf("%s%d%d",ch,&x,&y);
if(ch[0]==‘Q‘)printf("%d\n",ask(x,y));
else change(x,y);
}
return 0;
}
标签:说明 last www print 查询 define int 记录 math
原文地址:http://www.cnblogs.com/Stump/p/7900591.html