bzoj 2120 数颜色 (分块做法)
此篇文章主要讲修改操作
用pre[i]表示第i个元素的前一个相同元素的位置,问题变成在区间[l,r]里找大于l的数的个数,
(具体什么意思去其他地方看)默认值为最大值。
用ppp[i]表示颜色i最后出现的位置(针对这道题颜色最多1e6种,建一个1e6的数组即可)
color[i]表示第i个位置是什么颜色
总个数为n
1.建区块(网上有)
2.查询操作(网上有)
3.修改操作
这个是color数组
修改操作的主要问题是如何在序列后找到修改之前的颜色的第一个位置
和
修改之后的颜色前一个位置,后一个位置
这里就要用到ppp数组解决这个问题
上图下面的那个数组是ppp数组
比如将5号位置的3修改为2
那么我们要更改值的位置则为五号位置后面的3和2
问题就是如何寻找颜色2,3
很简单,如图这是一个链式结构,只要我们从ppp数组中找到相应元素的最后位置,在通过pre数组的值往前找就可以了
沿棕色的线寻找3
沿红色的线寻找2
找到位置改值再对相应的块进行重构修改就完成了。注意维护ppp数组的值始终保持为最后一个元素值
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#define inf 0x3f3f3f3f
using namespace std;
int a[205][205];
int pre[200005];
int color[200005];
int ppp[1000005];
int n,m,l,r;
void reset(int x)
{
int p=(x-1)/l;
for(int j=1;j<=l;j++)
{
a[p][j]=pre[p*l+j];
}
sort(a[p]+1,a[p]+l+1);
}
void build()
{
for(int i=0;i<r;i++)
{
for(int j=1;j<=l;j++)
{
a[i][j]=pre[i*l+j];
}
sort(a[i]+1,a[i]+l+1);
}
}
int search(int x,int y)
{
int ans=0;
int p=(x-1)/l+1;
int q=(y-1)/l;
if(p>=q)
{
for(int i=x;i<=y;i++)
if(pre[i]<x)
ans++;
return ans;
}
for(int i=x;i<=p*l;i++)
if(pre[i]<x)
ans++;
for(int i=q*l+1;i<=y;i++)
if(pre[i]<x)
ans++;
for(int i=p;i<q;i++)
{
ans+=lower_bound(a[i]+1,a[i]+l+1,x)-a[i]-1;
}
return ans;
}
void change(int x,int y)//位置x,颜色y.
{
int p=color[x];
color[x]=y;
int c=ppp[p];
if(c==x)
{
ppp[p]=pre[c];
}
else
{
while(pre[c]!=x)
c=pre[c];
pre[c]=pre[x];
reset(c);
}
c=ppp[y];
if(c<x)
{
pre[x]=c;
ppp[y]=x;
reset(x);
}
else if(pre[c]<x)
{
pre[x]=pre[c];
pre[c]=x;
reset(x);
reset(c);
}
else
{
while(pre[c]>x)
{
c=pre[c];
}
pre[x]=pre[c];
pre[c]=x;
reset(x);
reset(c);
}
}
int main()
{
//freopen("input.txt","r",stdin);
memset(ppp,0,sizeof(ppp));
memset(pre,inf,sizeof(pre));
pre[0]=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&color[i]);
if(ppp[color[i]]!=0)
pre[i]=ppp[color[i]];
else
pre[i]=0;
ppp[color[i]]=i;
}
l=floor(sqrt(n));
if(n%l>0)
r=n/l+1;
else
r=n/l;
build();
/*printf("%d %dff\n",l,r);
for(int i=1;i<=n;i++)
printf("%d ",pre[i]);
puts("");*/
int x,y;
char c[10];
for(int i=0;i<m;i++)
{
scanf("%s%d%d",c,&x,&y);
if(c[0]=='Q')
printf("%d\n",search(x,y));
else
change(x,y);
}
return 0;
}