Dynamic len 題解+代碼 (帶修改莫隊算法模板)

Description

有n個數編號從0→n-1,兩種操作:
Q L R:詢問編號爲L→R-1的數中共有多少種不同的數
M X Y:將編號爲X的數改爲Y
共有m個操作

Input

第一行兩個數n,m
接下來m行,每行有兩種形式,如題目描述

Output

對於每一個Q操作,輸出相應的答案

Sample Input

7 4
1 2 1 3 2 1 4
Q 1 6
M 3 2
Q 1 6
Q 3 5

Sample Output

3
2
1

Data Constraint

30% n,m<=10000
100% n,m<=50000
數的範圍<=1000000

Solution

首先,你得會莫隊算法。
對於一個[l,r]如果能夠O(1)O(1)修改到[l+1,r][l-1,r][l,r+1][l,r-1]
那麼就可以使用莫隊算法。
莫隊算法的基本做法就是離線輸入所有的詢問,以l所在的塊爲第一關鍵字,**r(不同於後面的r所在的塊)**爲第二關鍵字進行排序,然後依次做下去,一個區間到下一個區間的修改直接暴力即可。
時間複雜度爲O(nn)O(n\sqrt{n})
爲什麼呢?
暴力是分別暴力l和r的,對於l,同一個塊內不超過O(n)O(\sqrt{n}),不超過n\sqrt{n}個塊。對於r,每次逐漸增大,等到l跨過一個塊後又會變小,對於每個塊只會有一次變小所以每個塊O(n),不超過n\sqrt{n}個塊,總不超過O(nn)O(n\sqrt{n})
可以看看模板題,

小Z的襪子,我的博客請點此

這是不帶修改的,那帶修改的呢?
把[l,r]改爲[l,r,x],區間[l,r],第x次修改後的。同樣排序
所有的詢問,以l所在的塊爲第一關鍵字,r所在的塊爲第二關鍵字進行排序,x爲第三關鍵字排序,然後依次做下去,一個區間到下一個區間的修改直接暴力即可。
(當時寫錯了,感謝某大佬提醒,已修改)
複雜度自己證明。是根號級別的

另外,這裏的暴力是真正的暴力,從l到l’就是for i=l~l’,徹底的暴力。

對於這題,記錄一下每種有多少個,如果從0加到1則ans++,從1減到0則ans–,注意在修改時如果修改的不在l~r內,不需要修改ans

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define sz 1500
using namespace std;
int n,m,a[50100],bz[1000100],c[50100][3],tot,cot,ans[50100],d[50100],an;
struct note{
	int l,r,x,s;
};
note b[50100];
bool cnt(note x,note y)
{
	 return (x.l/sz<y.l/sz)||((x.l/sz==y.l/sz)&&(x.r/sz<y.r/sz))||((x.l/sz==y.l/sz)&&(x.r/sz==y.r/sz)&&(x.x<y.x));
}
int main()
{
	freopen("len.in","r",stdin);
	freopen("len.out","w",stdout);
	scanf("%d%d\n",&n,&m);
	fo(i,1,n) scanf("%d",&a[i]);
	scanf("\n");
	int jy=0;
	fo(i,1,m)
	{
		int x,y;char ch;scanf("%c%d%d\n",&ch,&x,&y);x++;
		if (ch=='Q') b[++tot].l=x,b[tot].r=y,b[tot].x=jy,b[tot].s=tot;
		else jy++,c[++cot][0]=x,c[cot][1]=y;
	}
	sort(b+1,b+tot+1,cnt);
	int l=b[1].l,r=b[1].r,x=b[1].x;an=0;
	fo(j,1,b[1].x) 
	{
		c[j][2]=a[c[j][0]];a[c[j][0]]=c[j][1];
	}
	fo(i,l,r){
		if (bz[a[i]]==0) an++;
		bz[a[i]]++;
	}
	ans[b[1].s]=an;
	fo(i,2,m)
	{
		if(b[i].x>x) 
		fo(j,x+1,b[i].x) 
		{
			if (c[j][0]>=l&&c[j][0]<=r){
			bz[a[c[j][0]]]--;
			if (bz[a[c[j][0]]]==0) an--;
			if (bz[c[j][1]]==0) an++;
			bz[c[j][1]]++;
			}
			c[j][2]=a[c[j][0]];a[c[j][0]]=c[j][1];
		}
		else 
		fd(j,x,b[i].x+1) 
		{
			if (c[j][0]>=l&&c[j][0]<=r){
			bz[a[c[j][0]]]--;
			if (bz[a[c[j][0]]]==0) an--;
			if (bz[c[j][2]]==0) an++;
			bz[c[j][2]]++;
			}
			a[c[j][0]]=c[j][2];
		}
		if (b[i].l>l)
		{
			fo(j,l,b[i].l-1){
				bz[a[j]]--;
				if (bz[a[j]]==0) an--;
				
			}
		}
		else
		{
			fd(j,l-1,b[i].l){
				if (bz[a[j]]==0) an++;
				bz[a[j]]++;
			}
		}
		if (b[i].r>r)
		{
			fo(j,r+1,b[i].r){
				if (bz[a[j]]==0) an++;
				bz[a[j]]++;
			}
		}
		else
		{
			fd(j,r,b[i].r+1){
				bz[a[j]]--;
				if (bz[a[j]]==0) an--;
			}
		}
		ans[b[i].s]=an;
		l=b[i].l;r=b[i].r;x=b[i].x;
	}
	fo(i,1,tot) printf("%d\n",ans[i]);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章