【洛谷P1903】【BZOJ2120】数颜色 / 维护队列【带修莫队】

题目大意:

题目链接:
洛谷:https://www.luogu.org/problemnew/show/P1903
BZOJ:https://www.lydsy.com/JudgeOnline/problem.php?id=2120

nn只画笔,维护以下操作:

  1. Q L RQ L R代表询问你从第LL支画笔到第RR支画笔中共有几种不同颜色的画笔。
  2. R P ColR P Col 把第PP支画笔替换为颜色ColCol

思路:

一开始看到这题兴奋的敲了一个分块,敲到最后才发现col106colleq 10^6而不是10510^5。。。
正解是带修莫队。
如果没有修改操作,那么这就是莫队的板子。
只要加上修改就可以了。


其实莫队的修改也是暴力。
我们把每一个修改记录下来,然后把每一个询问前所需要的修改数也记录下来。如果询问ii比询问i1i-1多了一些修改,那么就把这些修改改好,如果少了就改回去。
其实真的就是暴力。

void work(int x,int i)  //要做第x次修改,这次是询问i
{
	if (chg[x].x>=ask[i].l&&chg[x].x<=ask[i].r)  //在区间内修改才有贡献
	{
		cnt[a[chg[x].x]]--;
		if (!cnt[a[chg[x].x]]) sum--;
		if (!cnt[chg[x].val]) sum++;
		cnt[chg[x].val]++; 
	}
	swap(a[chg[x].x],chg[x].val);
	//交换之后,如果下次要改回来时就相当于把现在的值储存到原数组里
}

带修莫队平均最有复杂度大约是取Block=n3Block=sqrt[3]{n}。证明是不可能证明的XD
不知道为什么我敲的莫队跑的贼慢。不加Ofast,inlineOfast,inline的话要跑4s+4s+。请大佬斧正。


代码:

%:pragma GCC optimize("Ofast")
%:pragma GCC optimize("inline")
#include <cmath>
#include <cstdio>
#include <string>
#include <algorithm>
#define rr register
using namespace std;

const int N=50010,M=1000010;
int n,m,s,Q,T,l,r,sum,k,a[N],ans[N],cnt[M],pos[N];
char ch;

int read()
{
	int d=0;
	char ch=getchar();
	while (!isdigit(ch)) ch=getchar();
	while (isdigit(ch))
		d=(d<<3)+(d<<1)+ch-48,ch=getchar();
	return d;
}

void write(int x)
{
	if (x>9) write(x/10);
	putchar(x%10+48);
}

struct Ask
{
	int l,r,id,k;
}ask[N];

struct Change
{
	int x,val;
}chg[N];

bool cmp(Ask x,Ask y)
{
	if (pos[x.l]<pos[y.l]) return 1;
	if (pos[x.l]>pos[y.l]) return 0;
	return x.r<y.r;
}

void del(int x)
{
	cnt[a[x]]--;
	if (!cnt[a[x]]) sum--;
}

void add(int x)
{
	if (!cnt[a[x]]) sum++;
	cnt[a[x]]++;
}

void work(int x,int i)
{
	if (chg[x].x>=ask[i].l&&chg[x].x<=ask[i].r)
	{
		cnt[a[chg[x].x]]--;
		if (!cnt[a[chg[x].x]]) sum--;
		if (!cnt[chg[x].val]) sum++;
		cnt[chg[x].val]++;
	}
	swap(a[chg[x].x],chg[x].val);
}

int main()
{
	n=read(); Q=read();
	T=pow((double)n,(1.0/3.0));
	for (rr int i=1;i<=n;i++)
	{
		a[i]=read();
		pos[i]=(i-1)/T+1;
	}
	for (rr int i=1;i<=Q;i++)
	{
		while (ch=getchar()) if (ch=='Q'||ch=='R') break;
		if (ch=='Q')
		{
			m++;
			ask[m].l=read(); ask[m].r=read();
			ask[m].id=m; ask[m].k=s;
		}
		else
		{
			s++;
			chg[s].x=read(); chg[s].val=read();
		}
	}
	sort(ask+1,ask+1+m,cmp);
	l=1;
	for (rr int i=1;i<=m;i++)
	{
		for (;l<ask[i].l;l++) del(l);
		for (;l>ask[i].l;l--) add(l-1);
		for (;r<ask[i].r;r++) add(r+1);
		for (;r>ask[i].r;r--) del(r);
		for (;k<ask[i].k;k++) work(k+1,i);
		for (;k>ask[i].k;k--) work(k,i);
		ans[ask[i].id]=sum;
	}
	for (rr int i=1;i<=m;i++)
		write(ans[i]),putchar(10);
	return 0;
}
原文地址:https://www.cnblogs.com/hello-tomorrow/p/11997986.html