您的位置:首页 > 其它

bzoj 2120: 数颜色

2016-03-18 23:03 393 查看
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#define M 1000009
using namespace std;
int block,n,m,a[M],b[M],pre[M],pos[M],last[M],l[M],r[M],m1;
int ask(int a1,int a2)
{
int ans=0;
if(pos[a1]==pos[a2])
{
for(int i=a1;i<=a2;i++)
if(b[i]<a1)
ans++;
}
else
{
for(int i=a1;i<=r[pos[a1]];i++)
if(b[i]<a1)
ans++;
for(int i=l[pos[a2]];i<=a2;i++)
if(b[i]<a1)
ans++;
for(int i=pos[a1]+1;i<pos[a2];i++)
ans+=lower_bound(pre+l[i],pre+r[i]+1,a1)-pre-l[i];
}
return ans;
}
void jian(int i)
{
l[i]=(i-1)*block+1;
r[i]=min(n,i*block);
for(int j=l[i];j<=r[i];j++)
pre[j]=b[j];
sort(pre+l[i],pre+r[i]+1);
}
void gai(int x,int y)
{
for(int i=1;i<=n;i++)
last[a[i]]=0;
a[x]=y;
for(int i=1;i<=n;i++)
{
int t=b[i];
b[i]=last[a[i]];
if(t!=last[a[i]])
jian(pos[i]);
last[a[i]]=i;
}
}
int main()
{
scanf("%d%d",&n,&m1);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
block=(int)sqrt(n+log(2*n)/log(2));
m=n/block;
if(n%block)
m++;
for(int i=1;i<=n;i++)
{
b[i]=last[a[i]];
last[a[i]]=i;
pos[i]=(i-1)/block+1;
}
for(int i=1;i<=m;i++)
jian(i);
for(int i=1;i<=m1;i++)
{
char ch[5];
int a1,a2;
scanf("%s%d%d",ch,&a1,&a2);
if(ch[0]=='Q')
printf("%d\n",ask(a1,a2));
else
gai(a1,a2);
}
return 0;
}


暴力分块,每个点存下一个与他相同颜色的在哪,每个块内排序,找的时候首尾暴力判断每个点下一个颜色在不在区间外,不在就答案加加,中间二分。修改时重建每个点存的下一个点,

如果改了,就重建这个块。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: