【莫隊】P1903 [國家集訓隊]數顏色 / 維護隊列

  今天的內容是帶修莫隊html

例題:P1903 [國家集訓隊]數顏色 / 維護隊列

題目描述

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

一、 Q L R表明詢問你從第L支畫筆到第R支畫筆中共有幾種不一樣顏色的畫筆。git

二、 R P Col 把第P支畫筆替換爲顏色Col。github

爲了知足墨墨的要求,你知道你須要幹什麼了嗎?算法

輸入格式

第1行兩個整數N,M,分別表明初始畫筆的數量以及墨墨會作的事情的個數。ide

第2行N個整數,分別表明初始畫筆排中第i支畫筆的顏色。優化

第3行到第2+M行,每行分別表明墨墨會作的一件事情,格式見題幹部分。spa

輸出格式

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

輸入輸出樣例

輸入 #1
6 5
1 2 3 4 5 5
Q 1 4
Q 2 6
R 1 2
Q 1 4
Q 2 6
輸出 #1
4
4
3
4

說明/提示

對於100%的數據,N≤50000,M≤50000,全部的輸入數據中出現的全部整數均大於等於1且不超過10^6。code

本題可能輕微卡常數

來源:bzoj2120

本題數據爲洛谷自造數據,使用CYaRon耗時5分鐘完成數據製做。


帶修莫隊

  莫隊是一種很神奇的離線算法。能夠解決區間上的問題,經過排序和對詢問分塊來優化暴力。

  普通的莫隊題目都是給定的序列,不斷的詢問。

  那麼若是在詢問中夾雜了一些修改操做,莫隊還能作嗎?

  答案固然是能夠的。

  回顧一下莫隊的實現方法:

    1.提早預處理

    2.詢問分塊排序

    3.雙指針移動求解。

  惟一會由於修改而產生變化的操做就是3操做。

  能夠發現:當出現了修改操做以後,我當前詢問處理的區間可能就不是咱們原本要找的區間了。

  那麼怎麼辦呢?

  借鑑一下可持久化線段樹的思想:時光回溯

  咱們能夠先把帶修莫隊當作通常的莫隊來作,作完以後若是發現時間對不上就時光倒流。

  準確的說是:考慮兩個時間點的操做之間的代價。

  這麼說來,只要在普通莫隊的一堆 while 循環後面再加兩個就OK。

 while(now<q[i].t)
     change(++now);
 while(now>q[i].t)
     change(now--);    

代碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;

const int N=50005;
int col[N],n,m,sum[1000005],be[N];
int fans,qnum,cnum,ans[N];

struct qs{
    int l,r,t,id;
}q[N];
struct cs{
    int x,i;
}c[N];

bool cmp(qs x,qs y) {
    if(be[x.l]!=be[y.l])
        return x.l<y.l;
    if(be[x.r]!=be[y.r])
        return x.r<y.r;
    return x.t<y.t;
}

void upd1(int x) {
    if(!sum[col[x]])
        ++fans;
    ++sum[col[x]];
    return;
}

void upd2(int x) {
    --sum[col[x]];
    if(!sum[col[x]])
        --fans;
    return;
}

int l,r,now;

void change(int x) {
    if(c[x].i<=r&&c[x].i>=l) {
        --sum[col[c[x].i]];
        if(!sum[col[c[x].i]])
            --fans;
        if(!sum[c[x].x])
            ++fans;
        ++sum[c[x].x];
    }
    swap(c[x].x,col[c[x].i]);
    return;
}

int main()
{
    cin>>n>>m;
    int xx=pow(n,2.0/3.0);
    char opt; 
    for(int i=1;i<=n;i++) {
        cin>>col[i];
        be[i]=i/xx+1;
    }
    for(int i=1;i<=m;i++) {
        cin>>opt;
        if(opt=='Q') {
            ++qnum;
            cin>>q[qnum].l>>q[qnum].r;
            q[qnum].t=cnum;
            q[qnum].id=qnum;
        }
        else {
            ++cnum;
            cin>>c[cnum].i>>c[cnum].x;
        }
    }
    sort(q+1,q+qnum+1,cmp);
    l=r=fans=now=0;
    for(int i=1;i<=qnum;i++) {
        while(l<q[i].l)
            upd2(l++);
        while(l>q[i].l)
            upd1(--l);
        while(r>q[i].r)
            upd2(r--);
        while(r<q[i].r)
            upd1(++r);
        while(now<q[i].t)
            change(++now);
        while(now>q[i].t)
            change(now--);
        ans[q[i].id]=fans;
    }
    for(int i=1;i<=qnum;i++)
        cout<<ans[i]<<endl;
    return 0;
}
數顏色

 


雙倍經驗 CF940F Machine Learning

  戳這裏

相關文章
相關標籤/搜索