洛谷P1903 [国家集训队]数颜色 / 维护队列 带修改莫队

https://www.luogu.com.cn/problem/P1903

离线修改的莫队可以多增加一维的时间,然后变成[l,r,t]->[l+-1,r+-1,t+-1]

先按左端点块排序,再按右端点块排序,再按时间大小排序。

块的大小需要是n^(2/3),可以吧总复杂度变成O(n^(5/3)),优于n^2

实际上在1e5的数据下洛谷最大的点只跑了846ms,还没加读入优化

#include<bits/stdc++.h>
using namespace std;

const int maxl=1e6+10;

int n,m,len,tot,cntq,cntc;
int a[maxl],b[maxl],tmp[maxl],cnt[maxl];
int bel[maxl],ans[maxl];
struct qry
{
	int l,r,t,id;
}q[maxl];
struct mdf
{
	int pos,col;	
}c[maxl];
char s[2];

inline bool cmp(const qry &a,const qry &b)
{
	if(bel[a.l]==bel[b.l])
	{
		if(bel[a.r]==bel[b.r])
			return a.t<b.t;
		return bel[a.r]<bel[b.r];
	}
	return bel[a.l]<bel[b.l];
}

inline void prework()
{
	scanf("%d%d",&n,&m);
	len=pow(n,2.0/3.0);tot=0;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		bel[i]=(i-1)/len+1;		
	}
	int x,y;cntq=0;cntc=0;
	for(int i=1;i<=m;i++)
	{
		scanf("%s",s);
		scanf("%d%d",&x,&y);
		if(s[0]=='Q')
			q[++cntq]=qry{x,y,cntc,cntq};
		else
			c[++cntc]=mdf{x,y};
	}
	sort(q+1,q+1+cntq,cmp);
}

inline void mainwork()
{
	int l=1,r=0,clk=0,now=0;
	for(int i=1;i<=cntq;i++)
	{
		while(r<q[i].r)
			now+=!cnt[a[++r]]++;
		while(l>q[i].l)
			now+=!cnt[a[--l]]++;
		while(r>q[i].r)
			now-=!--cnt[a[r--]];
		while(l<q[i].l)
			now-=!--cnt[a[l++]];
		while(clk<q[i].t)
		{
			++clk;
			if(q[i].l<=c[clk].pos && c[clk].pos<=q[i].r)
			{	
				now-=!--cnt[a[c[clk].pos]];
				now+=!cnt[c[clk].col]++;
			}
			swap(a[c[clk].pos],c[clk].col);
		}
		while(clk>q[i].t)
		{
			if(q[i].l<=c[clk].pos && c[clk].pos<=q[i].r)
			{
				now-=!--cnt[a[c[clk].pos]];
				now+=!cnt[c[clk].col]++;
			}
			swap(a[c[clk].pos],c[clk].col);
			--clk;
		}
		ans[q[i].id]=now;
	}
}

inline void print()
{
	for(int i=1;i<=cntq;i++)
		printf("%d\n",ans[i]);
}

int main()
{
	prework();
	mainwork();
	print();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/liufengwei1/article/details/109153421
今日推荐