1. 程式人生 > >國家集訓隊——數顏色

國家集訓隊——數顏色

define ios code lap close lose img pos Go

墨墨購買了一套N支彩色畫筆(其中有些顏色可能相同),擺成一排,你需要回答墨墨的提問。墨墨會向你發布如下指令:

1、 Q L R代表詢問你從第L支畫筆到第R支畫筆中共有幾種不同顏色的畫筆。

2、 R P Col 把第P支畫筆替換為顏色Col。

題解:

做這道題之前不會帶修改莫隊,山神學會了之後手(嘴)把手(嘴)教我打代碼。

莫隊算法先放下,帶修改莫隊是醬的:記下所有的修改,同時為每個詢問加入一個時間標記,表示這個詢問發生時修改到了哪一步。求解之前記錄一個時間戳。每次求解一個詢問時,先按普通莫隊求解,然後查看當前時間戳和這個詢問的標記,不一樣的話就一個時間一個時間地改過去,同時修改答案。進行時間修改時,比如這道題,swap了修改的顏色和修改前的顏色,這樣可以讓之後發生時間倒流。

代碼:

技術分享圖片
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#define MXN 10000+1
#define MXC 1000000+1
struct Query{int l,r,t,id;}q[MXN];
struct change{int p,co;}c[MXN];
int block[MXN];
bool cmp(Query A,Query B){
    if(block[A.l]==block[B.l]){
        if(A.r==B.r) return
A.t<B.t; else return A.r<B.r; } else return block[A.l]<block[B.l]; } int n,m,x,y; int qsum,csum; std::string p; int color[MXN]; int man[MXC]; int ans[MXN]; void Change(int T,int i,int &temp){ if(c[T].p>=q[i].l&&c[T].p<=q[i].r){ man[color[c[T].p]]
--; if(man[color[c[T].p]]==0) temp--; man[c[T].co]++; if(man[c[T].co]==1) temp++; } std::swap(color[c[T].p],c[T].co); return; } int main(){ scanf("%d%d",&n,&m); int s=sqrt(n); for(int i=1;i<=n;i++){ scanf("%d",&color[i]); block[i]=i/s; } while(m--){ std::cin>>p; scanf("%d%d",&x,&y); if(p[0]==Q){ q[qsum].l=x; q[qsum].r=y; q[qsum].id=qsum; q[qsum++].t=csum; } if(p[0]==R){ c[++csum].p=x; c[csum].co=y; } } std::sort(q,q+qsum,cmp); int L=0,R=0,T=0,temp=0; for(int i=0;i<qsum;i++){ while(L<q[i].l){man[color[L]]--;if(man[color[L]]==0) temp--;L++;} while(L>q[i].l){L--;man[color[L]]++;if(man[color[L]]==1) temp++;} while(R<q[i].r){R++;man[color[R]]++;if(man[color[R]]==1) temp++;} while(R>q[i].r){man[color[R]]--;if(man[color[R]]==0) temp--;R--;} while(T<q[i].t){T++;Change(T,i,temp);} while(T>q[i].t){Change(T,i,temp);T--;} ans[q[i].id]=temp; } for(int i=0;i<qsum;i++) printf("%d\n",ans[i]); return 0; }
代碼

PS:壓行嚴重。

國家集訓隊——數顏色