【BZOJ2120】帶修改莫隊模板

BZOJ2120

普通莫隊一般是不帶修改的,但是有一些題目是需要修改的…
比如BZOJ2120。
這題如果沒有修改,那大概就是個莫隊裸題,但是它現在帶修改了,就需要一些操作了。
我們把對於詢問的結構體記錄一個上一次的修改,例如第5次詢問是在第3次修改之後進行的。
那麼如果我們需要詢問第5次詢問,現在修改還在第1次,我們就把修改改成2,3次之後,再進行詢問就可以了。思想上還是莫隊。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e6+7;
int n,m,qnum,cnum,block,Ans = 0;
int a[maxn],b[maxn],cnt[maxn],ans[maxn];
struct node
{
	int x,y,pre,id;
	bool operator<(const node &rhs)const
	{
		if(b[x]!=b[rhs.x]) return b[x]<b[rhs.x];
		if(b[y]!=b[rhs.y]) return b[y]<b[rhs.y];
		return pre<rhs.pre;
	}
}Q[maxn];
struct change
{
	int pos,x;
}C[maxn];
void add(int x)
{
	if(++cnt[x]==1) Ans++;
}
void del(int x)
{
	if(--cnt[x]==0) Ans--;
}
void gao(int now,int o)
{
	if(Q[o].x<=C[now].pos && Q[o].y>=C[now].pos)
	{
		if(--cnt[a[C[now].pos]]==0) Ans--;
		if(++cnt[C[now].x]==1) Ans++;
	}
	swap(a[C[now].pos],C[now].x);
}
void solve()
{
	int l = 1,r = 0,now = 0;
	for(int i=1;i<=qnum;i++)
	{
		while(l<Q[i].x) del(a[l++]);
		while(l>Q[i].x) add(a[--l]);
		while(r<Q[i].y) add(a[++r]);
		while(r>Q[i].y) del(a[r--]);
		while(now<Q[i].pre) gao(++now,i);
		while(now>Q[i].pre) gao(now--,i);
		ans[Q[i].id] = Ans;
	}
	for(int i=1;i<=qnum;i++) printf("%d\n",ans[i]);
}
int main()
{
	scanf("%d%d",&n,&m);
	block = sqrt(n*2.0/3.0);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",a+i);
		b[i] = i/block+1;
	}
	for(int i=0;i<m;i++)
	{
		char op[5];
		scanf("%s",op);
		if(op[0]=='Q')
		{
			int l,r;
			scanf("%d%d",&l,&r);
			Q[++qnum].x = l;
			Q[qnum].y = r;
			Q[qnum].pre = cnum;
			Q[qnum].id = qnum;
		}
		else if(op[0]=='R')
		{
			int x,y;
			scanf("%d%d",&x,&y);
			C[++cnum].pos = x;
			C[cnum].x = y;
		}
	}
	sort(Q+1,Q+1+qnum);
	solve();
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章