Loading

P5251 [LnOI2019]第二代图灵机 题解

很板子的一道题。

思路

由于操作中有关于颜色段相关的操作,又保证了数据随机,所以立马就可以想到 \(\text{ODT}\) ,又由于需要单点修改权值,并查询最大值,最小值,权值和,所以可以想到再用线段树去维护。

是不是十分的简单

实现细节

这里讲一讲一些实现的细节。

对于第三个和第四个查询操作,由于颜色种类不多,所以我们可以考虑用一个桶将所有的颜色种数存下来。

然后就可以用双指针去维护了。

当然,这里讲一个优化。

我们发现,桶在初始全部赋值为零时,并不需要完全把整个桶全部初始化。

只需要颜色种数多一点就可以了。

掌握了这个优化,轻松拿到 \(\text{rk1}\)(2022.3.5)。

时间复杂度:\(O(nlogn^2)\)

实际跑得飞快,只跑了 \(933ms\)

Code

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

const int N = 100010;

int n , m , c , a[N] , b[N] , vis[N];

struct ODT
{
    int l , r;
    mutable int v;
    inline bool operator<(const ODT &tmp) const
    {
        return l < tmp.l;
    }
};

set<ODT> odt;

struct ST
{
    int l , r , val , mx , mi;
}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 push_up(int p)
{
    t[p].val = t[p * 2].val + t[p * 2 + 1].val;
    t[p].mx = min(t[p * 2].mx , t[p * 2 + 1].mx);
    t[p].mi = max(t[p * 2].mi , t[p * 2 + 1].mi);
}

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

inline void update(int p , int k)
{
    if(t[p].l == t[p].r) { t[p].val = t[p].mx = t[p].mi = a[k]; return; }
    if((t[p].l + t[p].r) / 2 >= k) update(p * 2 , k);
    else update(p * 2 + 1 , k); push_up(p);
}

inline int ask1(int p , int l , int r)
{
    if(l <= t[p].l && t[p].r <= r) return t[p].val;
    int ans = 0 , mid = (t[p].l + t[p].r) / 2;
    if(l <= mid) ans += ask1(p * 2 , l , r); if(r > mid) ans += ask1(p * 2 + 1 , l , r);
    return ans;
}

inline int ask2(int p , int l , int r)
{
    if(l <= t[p].l && t[p].r <= r) return t[p].mx;
    int ans = 1e9 , mid = (t[p].l + t[p].r) / 2;
    if(l <= mid) ans = min(ans , ask2(p * 2 , l , r));
    if(r > mid) ans = min(ans , ask2(p * 2 + 1 , l , r));
    return ans;
}

inline int ask3(int p , int l , int r)
{
    if(l <= t[p].l && t[p].r <= r) return t[p].mi;
    int ans = 0 , mid = (t[p].l + t[p].r) / 2;
    if(l <= mid) ans = max(ans , ask3(p * 2 , l , r));
    if(r > mid) ans = max(ans , ask3(p * 2 + 1 , l , r));
    return ans;
}

inline auto split(int p)
{
    if(p > n) return odt.end();
    auto it = --odt.upper_bound((ODT){p , 0 , 0});
    if(it->l == p) return it;
    int l = it->l , r = it->r , v = it->v;
    odt.erase(it) , odt.insert((ODT){l , p - 1 , v});
    return odt.insert((ODT){p , r , v}).first;
}

inline void assign(int l , int r , int val)
{
    auto it2 = split(r + 1) , it1 = split(l);
    odt.erase(it1 , it2) , odt.insert((ODT){l , r , val});
}

inline int query1(int l , int r)
{
    memset(vis , 0 , (c+10) * sizeof(int));
    auto it2 = split(r + 1) , it1 = split(l);
    auto ls = it1 , rs = it1; int res = 1 , ans = 2e9; vis[rs->v] = 1;
    while(rs != it2)
    {
        if(res == c)
        {
            if(ls == rs) ans = min(ans , ask1(1 , ls->l , ls->r));
            else if(ls->r + 1 == rs->l) ans = min(ans , a[ls->r] + a[rs->l]);
            else ans = min(ans , a[ls->r] + a[rs->l] + ask1(1 , ls->r + 1 , rs->l - 1));
            vis[ls->v]-- , res -= (vis[ls->v] == 0) , ls++;
        }
        else rs++ , res += (vis[rs->v] == 0) , vis[rs->v]++;
    }
    return (ans == 2e9 ? -1 : ans);
}

inline bool check(set<ODT>::iterator l , set<ODT>::iterator r)
{
    if(l == r || (++l)-- == r) return 0; l++;
    for(auto i = l;i != r;i++) if(i->l != i->r) return 1;
    return 0;
}

inline int query2(int l , int r)
{
    memset(vis , 0 ,(c+10) * sizeof(int));
    int ans = ask3(1 , l , r);
    auto it2 = split(r + 1) , it1 = split(l) , ls = it1 , rs = it1;
    for(;rs != it2;rs++)
    {
        ++vis[rs->v];
        while(check(ls , rs)) vis[ls->v]-- , ls++;
        while(ls != rs && vis[rs->v] > 1) vis[ls->v]-- , ls++;
        if(ls != rs) ans = max(ans , ask1(1 , ls->r , rs->l));
    }
    return ans;
}

int main()
{
    n = read() , m = read() , c = read();
    for(int i = 1;i <= n;i++) a[i] = read();
    for(int i = 1;i <= n;i++) b[i] = read() , odt.insert((ODT){i , i , b[i]});
    build(1  , 1 , n);
    for(int i = 1;i <= m;i++)
    {
        int opt = read();
        if(opt == 1)
        {
            int x = read() , y = read();
            a[x] = y , update(1 , x);
        }
        if(opt == 2)
        {
            int l = read() , r = read() , x = read();
            assign(l , r , x);
        }
        if(opt == 3)
        {
            int l = read() , r = read();
            printf("%d\n" , query1(l , r));
        }
        if(opt == 4)
        {
            int l = read() , r = read();
            printf("%d\n" , query2(l , r));
        }
    }
    return 0;
} 

posted @ 2022-03-03 15:19  JiaY19  阅读(60)  评论(0编辑  收藏  举报