zoukankan      html  css  js  c++  java
  • 2016北京集训测试赛(十七)Problem C: 数组

    Description

    Solution

    线段树好题.
    我们考虑用last[i]表示(i)这个位置的颜色的上一个出现位置. 考虑以一个位置(R)为右端点的区间最远能向左延伸到什么位置: (L = max_{i le j} last[j]).
    而我们的答案就等于

    [sum_{i = 1}^n (i - (max_{1 le j le i} last[j])) = sum_{i = 1}^n i - sum_{i = 1}^n max_{1 le j le i} last[j] ]

    第一项可以直接计算, 考虑如何维护第二项.
    我们开一颗线段树, 假设一个节点所维护的区间是([L, R]), 则节点维护(sum_{i = L}^R max_{L le j le i} last[j]). 具体怎么实现, 看代码即可.

    #include <cstdio>
    #include <cctype>
    #include <set>
    #include <algorithm>
    #define iter set<int>::iterator
     
    using namespace std;
    namespace Zeonfai
    {
        inline int getInt()
        {
            int a = 0, sgn = 1; char c;
            while(! isdigit(c = getchar())) if(c == '-') sgn *= -1;
            while(isdigit(c)) a = a * 10 + c - '0', c = getchar();
            return a * sgn;
        }
    }
    const int N = (int)1e5;
    int n;
    int col[N + 1], pre[N + 1];
    set<int> st[N + 1];
    inline iter getPrevious(iter p) {return -- p;}
    inline iter getNext(iter p) {return ++ p;}
    struct segmentTree
    {
        struct node
        {
            int mx;
            long long sum;
        }nd[N << 2];
        long long work(int u, int L, int R, int val)
        {
            int mid = L + R >> 1;
            if(L == R) {return max(val, nd[u].mx);}
            else if(nd[u].mx <= val) {return (long long)(R - L + 1) * val;}
            else if(nd[u << 1].mx <= val) return (long long)val * (mid - L + 1) + work(u << 1 | 1, mid + 1, R, val);
            else return work(u << 1, L, mid, val) + nd[u].sum - nd[u << 1].sum;
        }
        inline void pushUp(int u, int L, int R)
        {
            int mid = L + R >> 1;
            nd[u].mx = max(nd[u << 1].mx, nd[u << 1 | 1].mx);
            nd[u].sum = (long long)nd[u << 1].sum + work(u << 1 | 1, mid + 1, R, nd[u << 1].mx);
        }
        void build(int u, int L, int R)
        {
            if(L == R) {nd[u].mx = nd[u].sum = pre[L]; return;}
            int mid = L + R >> 1;
            build(u << 1, L, mid); build(u << 1 | 1, mid + 1, R);
            pushUp(u, L, R);
        }
        inline void build() {build(1, 1, n);}
        void modify(int u, int L, int R, int pos, int val)
        {
            if(L == R) {nd[u].sum = nd[u].mx = val; return;}
            int mid = L + R >> 1;
            if(pos <= mid) modify(u << 1, L, mid, pos, val); else modify(u << 1 | 1, mid + 1, R, pos, val);
            pushUp(u, L, R);
        }
        inline void modify(int pos, int val) {modify(1, 1, n, pos, val);}
    }seg;
    int main()
    {
     
        #ifndef ONLINE_JUDGE
     
        freopen("array.in", "r", stdin);
        freopen("array.out", "w", stdout);
     
        #endif
     
        using namespace Zeonfai;
        n = getInt();
        for(int i = 1; i <= n; ++ i) st[i].clear();
        for(int i = 1; i <= n; ++ i)
        {
            col[i] = getInt();
            if(st[col[i]].empty()) pre[i] = 0; else pre[i] = *getPrevious(st[col[i]].find(i));
            st[col[i]].insert(i);
        }
        seg.build();
        int m = getInt();
        for(int i = 0; i < m; ++ i)
        {
            int opt = getInt();
            if(opt)
            {
                int pos = getInt(), x = getInt();
                iter p = getNext(st[col[pos]].find(pos));
                st[col[pos]].erase(st[col[pos]].find(pos));
                if(p != st[col[pos]].end()) pre[*p] = p == st[col[pos]].begin() ? 0 : *getPrevious(p);
                if(p != st[x].end()) seg.modify(*p, pre[*p]);
                col[pos] = x; st[x].insert(pos);
                pre[pos] = st[x].find(pos) == st[x].begin() ? 0 : *getPrevious(st[x].find(pos));
                p = getNext(st[x].find(pos)); if(p != st[x].end()) pre[*p] = pos;
                if(p != st[x].end()) seg.modify(*p, pre[*p]);
                seg.modify(pos, pre[pos]);
            }
            else printf("%lld
    ", (long long)n * (n + 1) / 2 - seg.nd[1].sum);
        }
    }
    
  • 相关阅读:
    ubuntu在桌面创建快捷方式
    ubuntu下安装VMware
    常用docker命令
    转:如何在Ubuntu 14.04中安装最新版Eclipse
    docker初安装的血泪史
    关于ubuntu中文输入调用不出来的解决办法,具体如正文。
    测试linux下磁盘的读写速率
    pidstat 命令详解(转载)
    TCP/IP 协议栈4层结构及3次握手4次挥手
    nginx反向代理原理及配置详解
  • 原文地址:https://www.cnblogs.com/ZeonfaiHo/p/7464954.html
Copyright © 2011-2022 走看看