• 题解 CF848C 【Goodbye Souvenir】


    (huge exttt{CF848C})

    前置:cdq分治,( exttt{P4390}) (即cdq分治解决单点修改,矩阵查询的问题)。

    此题便是 ( exttt{P4390}) 的巧妙转换。

    题意

    不做赘述。

    但是为了更好地做题,题中:

    数字 (X)([l,r]) 最后一次出现位置的下标减去第一次出现位置的下标。

    等价于:

    数字 (X)([l,r]) 中每次出现的下标相邻的差的绝对值。

    思路

    一个朴素的想法:

    • 修改:用 (set) 动态维护维护每个位置的数与之相同的前面的数的位置,时间复杂度 (O(log N))
    • 查询暴力一个一个查 (sum_{i=l}^{ile r} i- exttt{pre}_i ( exttt{pre}_i ge l)) ,时间复杂度(O(N))

    考虑优化查询。

    观察到每两个建立好的二元组 (( exttt{pre}_i,i)) 能对区间 ([l,r]) 产生贡献当且仅当:

    • ( exttt{pre}_i ge l)
    • (i le r)
    • 以及操作的相对时间 (T)(change exttt T le query exttt T)

    联系到 ( exttt{P4390}) ,这不就相当于是看成一个二维数对,点((x,y)) 就是上述二元组,查询的便是一个 ((l,l))((r,r)) 构成的矩阵。

    用cdq分治就可以解决了,cdq具体操作内容参考上题。(翻了翻 ( exttt{CF}) 上的记录或许还有其他做法,如莫队,扫描线...)。

    注意修改操作一定要修改完整,当要删除一个二位数对的贡献时,加入与之相反贡献的相同数对即可。

    代码

    int a, b, s[N + 10], top, q[N + 10], ans[N + 10];
    bool p[N + 10];
    set<int> st[N + 10];
    set<int>::iterator it;
    struct node
    {
        int opt, t, x, y, val;
        bool p;
    } ask[N + 10];
    
    inline bool cmp1(node &p1, node &p2)
    {
        return p1.x < p2.x || p1.x == p2.x && p1.opt < p2.opt;
    }
    
    inline bool cmp2(node &p1, node &p2)
    {
        return p1.t < p2.t;
    }
    
    inline void add(int n, int k)
    {
        for (; n <= a; n += n & -n)
            q[n] += k;
    }
    
    inline int query(int n)
    {
        if (!n)
            return 0;
        int res = 0;
        for (; n; n -= n & -n)
            res += q[n];
        return res;
    }
    
    inline void cdq(int l, int r)
    {
        if (l == r)
            return;
        int mid = (l + r) >> 1;
        cdq(l, mid);
        cdq(mid + 1, r);
        for (int i = mid + 1; i <= r; i++)
            ask[i].p = 1;
        sort(ask + l, ask + r + 1, cmp2);
        for (int i = l; i <= r; i++)
        {
            if (!ask[i].p)
            {
                if (ask[i].opt == 1)
                    add(ask[i].y, ask[i].val);
            }
            else
            {
                if (ask[i].opt == 2)
                    ans[ask[i].t] += query(ask[i].y) * ask[i].val;
            }
        }
        for (int i = l; i <= r; i++)
        {
            if (!ask[i].p && ask[i].opt == 1)
                add(ask[i].y, -ask[i].val);
            ask[i].p = 0;
        }
    }
    
    signed main()
    {
        // freopen("in1.in", "r", stdin);
        a = read();
        b = read();
        for (int i = 1; i <= a; i++)
        {
            s[i] = read();
            if (!st[s[i]].empty())
                ask[++top] = (node){1, 0, *st[s[i]].rbegin(), i, i - *st[s[i]].rbegin()};
            st[s[i]].insert(i);
        }
        int opt, x, y, z, w;
        for (int i = 1; i <= b; i++)
        {
            opt = read();
            x = read();
            y = read();
            if (opt == 1)
            {
                //delete
                z = w = 0;
                it = st[s[x]].find(x);
                if (it != st[s[x]].begin())
                {
                    --it;
                    ask[++top] = (node){1, i, *it, x, -(x - *it)};
                    z = *it;
                    ++it;
                }
                ++it;
                if (it != st[s[x]].end())
                    ask[++top] = (node){1, i, x, *it, -(*it - x)}, w = *it;
                if (z && w)
                    ask[++top] = (node){1, i, z, w, w - z};
                st[s[x]].erase(x);
                //insert
                z = w = 0;
                st[y].insert(x);
                it = st[y].find(x);
                if (it != st[y].begin())
                {
                    --it;
                    ask[++top] = (node){1, i, *it, x, x - *it};
                    z = *it;
                    ++it;
                }
                ++it;
                if (it != st[y].end())
                    ask[++top] = (node){1, i, x, *it, *it - x}, w = *it;
                if (z && w)
                    ask[++top] = (node){1, i, z, w, z - w};
                s[x] = y;
            }
            else
            {
                p[i] = 1;
                ask[++top] = (node){2, i, x - 1, x - 1, 1};
                ask[++top] = (node){2, i, x - 1, y, -1};
                ask[++top] = (node){2, i, y, x - 1, -1};
                ask[++top] = (node){2, i, y, y, 1};
            }
        }
        sort(ask + 1, ask + top + 1, cmp1);
        cdq(1, top);
        for (int i = 1; i <= b; i++)
            if (p[i])
                printf("%lld
    ", ans[i]);
        return 0;
    }
    
  • 相关阅读:
    认证和授权学习2:springboot中快速使用spring security
    认证和授权学习1基于session的认证授权流程
    activiti学习11历史表和历史查询
    activiti学习10任务监听器的使用
    Vue源码阅读之VNode虚拟DOM(二)
    Vue源码阅读之Vue构造函数(一)
    useEffect使用指南
    从零搭建React+TypeScript的后台项目(三)
    从零搭建React+TypeScript的后台项目(二)
    从零搭建React+TypeScript的后台项目(一)
  • 原文地址:https://www.cnblogs.com/RedreamMer/p/14465473.html
Copyright © 2020-2023  润新知