这是一个很菜的 Oier 的博客|

Hanx16Msgr

园龄:2年8个月粉丝:12关注:3

2022-07-06 09:23阅读: 18评论: 0推荐: 0

Luogu P1903 [国家集训队] 数颜色 / 维护队列

Luogu P1903(带修莫队)

Luogu P1903

莫队算法是解决已知 [l,r] 答案后求 [l1,r] 或是 [l,r+1] 答案的一类算法,只要可以在 O(1) 的时间内转移,都可以使用莫队算法。

本题除了单纯的查询 [l,r] 的答案这一操作,还有修改这一操作,显然普通莫队无法胜任这个问题,这时候就要使用带修改的莫队算法。

与普通的莫队算法相比,带修莫队多了一个时间轴 t ,而这一多出的时间轴使得这种莫队算法支持修改操作。

具体实现方式与普通莫队相同,只不过在状态转移的时候要根据时间进行修改操作,如果前者 t1 大于后者 t2 ,那么就要将 [t1,t2] 之间的修改操作撤销,反之则是进行修改。

莫队算法的时间复杂度受块长影响很大,本题中块长取 n23 可以使得整体时间复杂度为最优的 O(n53)

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<limits.h>
#include<cmath>
#define mem(a,b) memset(a,b,sizeof(a));
using namespace std;
template<typename T> void read(T &k)
{
 	k=0;
	T flag=1;char b=getchar();
	while (b<'0' || b>'9') {flag=(b=='-')?-1:1;b=getchar();}
	while (b>='0' && b<='9') {k=(k<<3)+(k<<1)+(b^48);b=getchar();}
	k*=flag;
}
const int _SIZE=133333,_MAXN=1e6;
int n,m;
int a[_SIZE+5],cnt[_MAXN+5],ans[_SIZE+5];
int len,sum;
struct QUERY{
	int l,r,t,id;
}que[_SIZE+5],mod[_SIZE+5];
void add(int x)
{
	sum+=!cnt[x]++;
}
void del(int x)
{
	sum-=!--cnt[x];
}
void update(int x,int t)
{
	if (que[x].l<=mod[t].l && mod[t].l<=que[x].r)
	{
		del(a[mod[t].l]);
		add(mod[t].r);
	}
	swap(a[mod[t].l],mod[t].r);
}
bool cmp(QUERY x,QUERY y)
{
	if (x.l/len!=y.l/len) return x.l<y.l;
	if (x.r/len!=y.r/len) return x.r<y.r;
	return x.t<y.t;
}
int cntq,cntm;
int main()
{
	read(n);read(m);
	len=pow(n,0.66);
	for (int i=1;i<=n;i++) read(a[i]);
	for (int i=1;i<=m;i++)
	{
		char com[5];scanf("%s",com);
		int _t1,_t2;read(_t1),read(_t2);
		if (com[0]=='Q')
		{
			cntq++,
			que[cntq].id=cntq,que[cntq].l=_t1,
			que[cntq].r=_t2,que[cntq].t=cntm;
		}
		else
		{
			cntm++,
			mod[cntm].l=_t1,mod[cntm].r=_t2;
		}
	}
	sort(que+1,que+cntq+1,cmp);
	int lcur=1,rcur=0,tcur=0;
	for (int i=1;i<=cntq;i++)
	{
		while (lcur>que[i].l) add(a[--lcur]);
		while (lcur<que[i].l) del(a[lcur++]);
		while (rcur>que[i].r) del(a[rcur--]);
		while (rcur<que[i].r) add(a[++rcur]);
		while (tcur<que[i].t) update(i,++tcur);
		while (tcur>que[i].t) update(i,tcur--);
		ans[que[i].id]=sum;
	}
	for (int i=1;i<=cntq;i++) printf("%d\n",ans[i]);
	return 0;
}
posted @   Hanx16Msgr  阅读(18)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起