BZOJ2120 數顏色(帶修改莫隊)

本文版權歸ljh2000和博客園共有,歡迎轉載,但須保留此聲明,並給出原文連接,謝謝合做。ios

 

 


本文做者:ljh2000
做者博客:http://www.cnblogs.com/ljh2000-jump/
轉載請註明出處,侵權必究,保留最終解釋權!

 

Description

墨墨購買了一套N支彩色畫筆(其中有些顏色可能相同),擺成一排,你須要回答墨墨的提問。墨墨會像你發佈以下指令: 一、 Q L R表明詢問你從第L支畫筆到第R支畫筆中共有幾種不一樣顏色的畫筆。 二、 R P Col 把第P支畫筆替換爲顏色Col。爲了知足墨墨的要求,你知道你須要幹什麼了嗎?算法

Input

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

Output

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

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。blog

 

 
正解:帶修改莫隊
解題報告:
  這道題的數據範圍很小,之前寫過兩次,不過用的是暴力和分塊。
  今天學可修改的莫隊,發現這是一道模板題就順便寫了。
  由於莫隊是經過改變詢問的順序來下降總體複雜度,而帶修改的話就沒辦法處理前後順序的問題了。咱們考慮加入修改操做以後如何保證算法複雜度。
  由於查詢操做只有在查詢操做以前的全部修改操做完成以後才能保證正確性,也就是說我只要記錄了以前有多少個修改操做,而後在執行到當前查詢的時候我把多進行的修改操做還原,少進行的再進行修改就能夠保證個人正確性。
  同時爲了保證複雜度,採起的策略是對於每一個詢問按$(l/block,r/block,time)$排序(分別表示l所在的塊、r所在的詢問以前的修改次數),再順序完成,根據複雜度證實能夠保證複雜度上界爲$O(n^ {\frac{5}{3}} )$。
 
 1 //It is made by ljh2000
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <algorithm>
 8 #include <ctime>
 9 #include <vector>
10 #include <queue>
11 #include <map>
12 #include <set>
13 #include <string>
14 using namespace std;
15 typedef long long LL;
16 const int MAXN = 10011;
17 int n,m,a[MAXN],last[MAXN],cnt1,cnt2,block;
18 int L,R,head,ans,cnt[1000011],A[MAXN];
19 char ch[12];
20 struct ask{int l,r,lb,rb,tim,id;}q[MAXN];
21 struct modify{int x,y,last;}r[MAXN];
22 inline bool cmp(ask q,ask qq){ 
23     if(q.lb==qq.lb) {
24         if(q.rb==qq.rb) return q.tim<qq.tim;
25         return q.rb<qq.rb;
26     }
27     return q.lb<qq.lb;
28 }
29 inline int getb(int x){ return (x-1)/block+1; }
30 inline int getint(){
31     int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
32     if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
33 }
34 
35 inline void change(int x,int col){
36     if(L<=x&&x<=R) {
37         cnt[a[x]]--; if(cnt[a[x]]==0) ans--;
38         a[x]=col;
39         if(cnt[a[x]]==0) ans++;    cnt[a[x]]++; 
40     }
41     else a[x]=col;
42 }
43 
44 inline void update(int x,int type){
45     int cun=cnt[a[x]]; cnt[a[x]]+=type;
46     if(cun==0 && cnt[a[x]]==1) ans++;
47     else if(cun==1 && cnt[a[x]]==0) ans--;
48 }
49 
50 inline void work(){
51     n=getint(); m=getint();    for(int i=1;i<=n;i++) a[i]=getint(),last[i]=a[i];
52     block=sqrt(n);
53     for(int i=1;i<=m;i++) {
54         scanf("%s",ch);
55         if(ch[0]=='R') {
56             r[++cnt1].x=getint();
57             r[cnt1].y=getint();
58             r[cnt1].last=last[r[cnt1].x];
59             last[r[cnt1].x]=r[cnt1].y;
60         }
61         else{
62             q[++cnt2].l=getint(); q[cnt2].r=getint(); q[cnt2].id=cnt2;
63             q[cnt2].lb=getb(q[cnt2].l); q[cnt2].rb=getb(q[cnt2].r);
64             q[cnt2].tim=cnt1; 
65         }
66     }
67     sort(q+1,q+cnt2+1,cmp); L=1; R=0; head=0;
68     for(int i=1;i<=cnt2;i++) {
69         while(head>q[i].tim) {
70             change(r[head].x,r[head].last);
71             head--;
72         }
73         while(head<q[i].tim) {
74             head++;
75             change(r[head].x,r[head].y);
76         }
77         while(R<q[i].r) R++,update(R,1);
78         while(L>q[i].l) L--,update(L,1);
79         while(R>q[i].r) update(R,-1),R--;
80         while(L<q[i].l) update(L,-1),L++;
81         A[q[i].id]=ans;
82     }
83     for(int i=1;i<=cnt2;i++) printf("%d\n",A[i]);
84 }
85 
86 int main()
87 {
88     work();
89     return 0;
90 }
相關文章
相關標籤/搜索