BZOJ2120&&洛谷P1903 [国家集训队]数颜色

带修莫队的裸题,带修莫队我们加入了修改操作,看起来不可做,但我们可以记录当前查询操作的上一个修改操作last,一个已经修改now,如果now>last说明当前查询在上次修改之前,所以要将多改的还原,若now<last说明还需要改,那么改过过来就行了,这道题在洛谷上加强了数据,需要玄学莫队,将分块大小block=sqrt(n)改为block=pow(n,0.6666666666)也就是n^(2/3),不知道为啥,大佬们说的,除去修改,这就和我上一篇博客一样了

代码

//By AcerMo 
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define swap(x, y) x^=y,y^=x,x^=y
using namespace std;
const int M=2e6+10;
struct Mo{int l,r,id,la;}e[M];
struct Ch{int poi,val;}g[M];
int n,m,c[M],que[M];
int cnt=0,tot=0,ans=0;
int block,bloc[M],col[M];
inline bool cmp1(Mo a,Mo b)
{
    if (bloc[a.l]!=bloc[b.l]) return a.l<b.l;
    if (bloc[a.r]!=bloc[b.r]) return a.r<b.r;
    return a.la<b.la;
}
inline int read()
{
	int x=0;char ch=getchar();
	while (ch>'9'||ch<'0') ch=getchar();
	while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return x;
}
inline void change(int x,int i)
{
    if(g[x].poi>=e[i].l&&g[x].poi<=e[i].r)
    {
        if(--col[c[g[x].poi]]==0) ans--;
        if(++col[g[x].val]==1) ans++; 
    }
    return (void)(swap(g[x].val,c[g[x].poi]));
}
inline void slove()
{
	int l=1,r=0,now=0;
	for (int i=1;i<=tot;i++)
	{
		while (l<e[i].l) if (--col[c[l++]]==0) ans--;
		while (l>e[i].l) if (++col[c[--l]]==1) ans++;
		while (r<e[i].r) if (++col[c[++r]]==1) ans++;
		while (r>e[i].r) if (--col[c[r--]]==0) ans--;
		while(now<e[i].la) change(++now,i); 
        while(now>e[i].la) change(now--,i);
		que[e[i].id]=ans;
	}
	return ;
}
int main()
{
	n=read();m=read();block=pow(n,0.6666666666);
	for (int i=1;i<=n;i++) c[i]=read();
	for (int i=1;i<=n;i++) bloc[i]=i/block+1;
	for (int i=1;i<=m;i++)
	{
		char fl[5];scanf("%s",fl);
		if (fl[0]=='Q')
		{
			e[++tot].l=read();e[tot].r=read();
			e[tot].la=cnt;e[tot].id=tot;
		}
		else
		{
			g[++cnt].poi=read();g[cnt].val=read();
		}
	}
	sort(e+1,e+tot+1,cmp1);
	slove();
	for (int i=1;i<=tot;i++)
	printf("%d\n",que[i]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/acerandaker/article/details/81057293
今日推荐