CF1209G2 Into Blocks (hard version) 题解

思路比较困难的一道线段树题目。

考虑对于一段一段的混合颜色区间,我们的最优策略显然是留下其中元素数量最多的颜色。

比如:

12221123343

这就是两个颜色区间,一个是 1222112,另一个是 3343

其中第一个留下 2,第二个留下 3 显然是最优的。

考虑利用线段树来维护这个东西。

我们考虑将每个元素维护 si,ti 分别为元素的起始位置和末尾位置。

可以利用 set 来维护。

维护一个 b 数组。

对于每个颜色,就在 b 数组上对于 [si,ti) 范围内全部加 1

可以发现,b 数组内为零的每一位都是一个混合颜色区间的末尾。

那么我们同时也可以在每一个颜色的起始位置上存放这个颜色的元素个数。

我们就可以维护这里面每一个区间的最大值。

使用线段树来维护。

讲一下实现细节。

维护一个 ls,rs,sum,maxx,minn

ls 维护的是靠左的最大值。

rs 维护的是靠右的最大值。

sum 维护的是最大值之和。

maxx 维护的是整个区间的最大值之和。

minn 维护的是这个区间里面 b 数组的最小值。

可以很简单的发现,如果一个区间里面 b 数组没有零,那么就随便上传数据。

所以我们可以根据有零的区间来讨论。

  1. 如果 minnl<minnr 也就是零在左边。

    那么,这个区间靠右的最大值是右区间的最大值和左区间靠右的最大值的最大值,最大值之和就是左区间的最大值之和。

  2. 如果 minnl>minnr 也就是零在右边。

    那么,这个区间靠左的最大值是左区间的最大值和右区间靠左的最大值的最大值,最大值之和就是右区间的最大值之和。

  3. 如果 minnl>minnr 也就是两边都有零。

    那么,最大值之和就是右区间的最大值之和和左区间的最大值之和和左区间靠右的最大值与右区间靠左的最大值中的最大值之和。

其他的就可以直接看代码了。

#include <bits/stdc++.h>
using namespace std;

const int N = 200010;

int n , m , a[N];
set<int> q[N];

struct Tree
{
    int l , r;
    int ls , rs , sum;
    int minn , maxx , tag;
}t[N * 4];

inline int read()
{
    int asd = 0 , qwe = 1; char zxc;
    while(!isdigit(zxc = getchar())) if(zxc == '-') qwe = -1;
    while(isdigit(zxc)) asd = asd * 10 + zxc - '0' , zxc = getchar();
    return asd * qwe;
}

inline void build(int p , int l , int r)
{
    t[p].l = l , t[p].r = r;
    if(l == r) return;
    build(p * 2 , l , (l + r) / 2);
    build(p * 2 + 1 , (l + r) / 2 + 1 , r);
}

inline void pushDown(int p)
{
    t[p * 2].minn += t[p].tag;
    t[p * 2 + 1].minn += t[p].tag;
    t[p * 2].tag += t[p].tag;
    t[p * 2 + 1].tag += t[p].tag;
    t[p].tag = 0;
}

inline void pushUp(int p)
{
    int l = p * 2 , r = p * 2 + 1;
    t[p].minn = min(t[l].minn , t[r].minn);
    t[p].maxx = max(t[l].maxx , t[r].maxx);
    if(t[l].minn < t[r].minn)
    {
        t[p].ls = t[l].ls;
        t[p].sum = t[l].sum;
        t[p].rs = max(t[l].rs , t[r].maxx);
    }
    if(t[l].minn > t[r].minn)
    {
        t[p].rs = t[r].rs;
        t[p].sum = t[r].sum;
        t[p].ls = max(t[r].ls , t[l].maxx);
    }
    if(t[l].minn == t[r].minn)
    {
        t[p].rs = t[r].rs;
        t[p].ls = t[l].ls;
        t[p].sum = t[l].sum + t[r].sum + max(t[l].rs , t[r].ls);
    }
}

inline void update1(int p , int l , int r , int k)
{
    if(l > r) return;
    if(l <= t[p].l && t[p].r <= r)
    {
        t[p].minn += k;
        t[p].tag += k;
        return;
    }
    pushDown(p);
    int mid = (t[p].l + t[p].r) / 2;
    if(l <= mid) update1(p * 2 , l , r , k);
    if(r > mid) update1(p * 2 + 1 , l , r , k);
    pushUp(p);
}

inline void update2(int p , int x , int k)
{
    if(t[p].l == t[p].r)
    {
        t[p].maxx += k;
        t[p].ls += k;
        return;
    }
    pushDown(p);
    int mid = (t[p].l + t[p].r) / 2;
    if(x <= mid) update2(p * 2 , x , k);
    if(x > mid) update2(p * 2 + 1 , x , k);
    pushUp(p);
}

inline void updateUsed(int col , int k)
{
    int siz = q[col].size();
    if(!siz) return;
    update1(1 , *q[col].begin() , *(--q[col].end()) - 1 , k);
    update2(1 , *q[col].begin() , k * siz);
}

inline int ask()
{
    return n - t[1].sum - t[1].ls - t[1].rs;
}

int main()
{
    int maxA = 0;
    n = read() , m = read();
    for(int i = 1;i <= n;i++)
        a[i] = read() , q[a[i]].insert(i),
        maxA = max(maxA , a[i]);
    build(1 , 1 , n);
    for(int i = 1;i <= maxA;i++)
        if(!q[i].empty())
            updateUsed(i , 1);
    printf("%d\n" , ask());
    for(int i = 1;i <= m;i++)
    {
        int x = read() , y = read();
        int col = a[x];
        updateUsed(col , -1) , q[col].erase(x);
        updateUsed(col ,  1) , updateUsed(y , -1);
        q[y].insert(x) , updateUsed(y ,  1) , a[x] = y;
        printf("%d\n" , ask());
    }
    return 0;
}

作者:JiaY19

出处:https://www.cnblogs.com/JiaY19/p/16755486.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   JiaY19  阅读(123)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
more_horiz
keyboard_arrow_up light_mode palette
选择主题
点击右上角即可分享
微信分享提示