題解 夢幻布丁

2022-04-29 22:12:12 字數 1277 閱讀 7699

\(question\)

題目大意:給乙個顏色序列,待修改,求區間顏色段數。

\(solution\)

考慮線段樹合併。

對於每乙個顏色建乙個線段樹,維護每個顏色出現的位置。同時維護區間的顏色段數,以及最左端、最右端的顏色位置。

於是,對於合併顏色\(x,y\).,·將它們對應線段樹合併即可。合併時,當一樹為空時,直接返回;當遞迴到葉子時,左右均為該處\(pos\).顏色段為1,返回即可。

對於插入時,與合併處理邊界一樣。

維護資訊時,左端資訊優先考慮左子樹,右端資訊優先考慮右子樹,總資訊將左右顏色段相加,但若兩端相交處顏色相同,則需要-1.

修改時一同維護\(ans.\)即可。

(蒟蒻第一次寫非權值線段樹的線段樹合併)

\(\text\)

#includeusing namespace std;

#define int long long

const int maxn=1e6+10;

int n,m,ans;

int rt[maxn],ch[maxn<<5][2],rub[maxn<<5],tot,cnt;

int a[maxn],ls[maxn<<5],rs[maxn<<5],ms[maxn<<5];

inline int build()

inline void del(int x)

inline void pushup(int x)

void modify(int &p,int l,int r,int pos)

int mid=l+r>>1;

if(pos<=mid)modify(ch[p][0],l,mid,pos);

else modify(ch[p][1],mid+1,r,pos);

pushup(p);

}int merge(int x,int y,int l,int r)

if(l==r)

int mid=l+r>>1;

ch[x][0]=merge(ch[x][0],ch[y][0],l,mid);

ch[x][1]=merge(ch[x][1],ch[y][1],mid+1,r);

del(y);pushup(x);return x;

}inline void solve()

void change(int x,int y)

signed main()

int q=m;

for(;q;q--)

} return 0;

}

HNOI2009 夢幻布丁

題意 n個布丁擺成一行,進行m次操作.每次將某個顏色的布丁全部變成另一種顏色的,然後再詢問當前一共有多少段顏色.例如顏色分別為1,2,2,1的四個布丁一共有3段顏色.對每個顏色的位置維護鍊錶。合併兩個顏色,連線鍊錶,統計貢獻。統計貢獻的複雜度是與鍊錶長度有關的。如果遍歷長度短的鍊錶那麼複雜度自然更小...

HNOI2009 夢幻布丁

n個布丁擺成一行,進行m次操作.每次將某個顏色的布丁全部變成另一種顏色的,然後再詢問當前一共有多少段顏色.例如顏色分別為1,2,2,1的四個布丁一共有3段顏色.輸入格式 第一行給出n,m表示布丁的個數和好友的操作次數.第二行n個數a1,a2.an表示第i個布丁的顏色從第三行起有m行,對於每個操作,若...

HNOI2009 夢幻布丁

題目鏈結 把每一種數字想象成乙個佇列。如果暴力合併,時間複雜度必然很高,考慮啟發式合併 每次把數字少的佇列合併到數字多的佇列上去。每次合併,若數字少的佇列數字個數為 s 則合併之後產生新佇列的大小必定不小於 2 s 時間複雜度 o n log n 這樣合併產生了乙個問題 即原來要求將 a 全部變為 ...