1. 程式人生 > >【bzoj2120: 數顏色】帶修改莫隊

【bzoj2120: 數顏色】帶修改莫隊

2120: 數顏色

Time Limit: 6 Sec  Memory Limit: 259 MB
Submit: 6501  Solved: 2593
[Submit][Status][Discuss]

Description

墨墨購買了一套N支彩色畫筆(其中有些顏色可能相同),擺成一排,你需要回答墨墨的提問。墨墨會像你釋出如下指令: 1、 Q L R代表詢問你從第L支畫筆到第R支畫筆中共有幾種不同顏色的畫筆。 2、 R P Col 把第P支畫筆替換為顏色Col。為了滿足墨墨的要求,你知道你需要幹什麼了嗎?

Input

第1行兩個整數N,M,分別代表初始畫筆的數量以及墨墨會做的事情的個數。第2行N個整數,分別代表初始畫筆排中第i支畫筆的顏色。第3行到第2+M行,每行分別代表墨墨會做的一件事情,格式見題幹部分。

Output

對於每一個Query的詢問,你需要在對應的行中給出一個數字,代表第L支畫筆到第R支畫筆中共有幾種不同顏色的畫筆。

Sample Input

6 5
1 2 3 4 5 5
Q 1 4
Q 2 6
R 1 2
Q 1 4
Q 2 6

Sample Output

4
4
3
4

HINT

對於100%的資料,N≤10000,M≤10000,修改操作不多於1000次,所有的輸入資料中出現的所有整數均大於等於1且不超過10^6。


剛開始忘了莫隊有個排序,,就直接暴力了,沒想到就過了,後來發現別人跑的比我的快很多,就想起來了。。。。

我們把修改操作和查詢操作分開來,莫隊一樣莫隊,我們在查詢的時候判斷這個查詢前面本來有多少個修改操作(一個查詢操作前的修改操作都是會影響當次查詢操作的),可以同莫隊類似的操作,如果還有沒操作的修改就修改,如果修改的多了就回撤回去。

由於我們有三個關鍵字,我們按照 l.block r.block time 這三個關鍵字順序排序,然後正常莫隊就好了。

為什麼要這樣排,我也不大清楚,據說這樣可以保證複雜度在O(n^(5/3))以內。這題資料水,暴力也沒壓力。

#include<cstdio>
#include<cmath>
#include<algorithm>
#define N 1000005
using namespace std;
int n,m,L,R,l,r,c[N],num[N],Num,cnt,cnt1,point;
int ans[10005],sz,vis[10005];
char ch[2];
struct he{
	int l,r,d,p,num,lst,l1,r1;
}q[10005],q1[10005];
bool cmp(he a,he b){
	if(a.l1==b.l1){
		if(a.r1==b.r1) return a.num<b.num;
		return a.r1<b.r1;
	}	
	return a.l1<b.l1;
}
int main(){
	freopen("1.in","r",stdin);
	freopen("1.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&c[i]);
	L=1;R=0;
	sz=sqrt(n)+1;
	for(int i=1;i<=m;i++){
		scanf("%s%d%d",ch,&l,&r);
		if(ch[0]=='Q'){
			cnt++;
			q[cnt].l=l;q[cnt].r=r;q[cnt].num=cnt1;q[cnt].p=cnt;
			q[cnt].l1=(l-1)/sz;q[cnt].r1=(r-1)/sz;
		}
		else {
			cnt1++;
			q1[cnt1].l=l;q1[cnt1].r=r;
		}
	}
	sort(q+1,q+1+cnt,cmp);
	
	point=0;
	for(int i=1;i<=cnt;i++){
		int l=q[i].l,r=q[i].r;
			while(R<r) {
				R++;
				num[c[R]]++;
				if(num[c[R]]==1) Num++;
			}
			while(R>r){
				num[c[R]]--;
				if(num[c[R]]==0) Num--;
				R--;
			}
			while(L>l){
				L--;
				num[c[L]]++;
				if(num[c[L]]==1) Num++;
			}
			while(L<l){
				num[c[L]]--;
				if(num[c[L]]==0) Num--;
				L++;
			}
			while(point<q[i].num){
				point++;
				if(L<=q1[point].l&&q1[point].l<=R){
					num[c[q1[point].l]]--;
					if(num[c[q1[point].l]]==0) Num--;
					num[q1[point].r]++;
					if(num[q1[point].r]==1) Num++;
				}
				q1[point].lst=c[q1[point].l];
				c[q1[point].l]=q1[point].r;
			}
			while(point>q[i].num){
				if(L<=q1[point].l&&q1[point].l<=R){
					num[q1[point].r]--;
					if(num[q1[point].r]==0) Num--;
					num[q1[point].lst]++;
					if(num[q1[point].lst]==1) Num++;			
				}
				c[q1[point].l]=q1[point].lst;
				point--;
			}
			ans[q[i].p]=Num;
	}
	for(int i=1;i<=cnt;i++)
		printf("%d\n",ans[i]);
}