zoukankan      html  css  js  c++  java
  • 【2020ICPC·小米 网络选拔赛第一场-E】Phone Network

    题目链接:https://ac.nowcoder.com/acm/contest/7501/E

    题目大意

    给定(n)个数的序列,对于每一个(m),求最短的涵盖从(1)(i)的线段的长度。

    思路

    看了题解之后只剩下:妙啊。

    题解已经说得很清楚了,这里复读一遍重新整理一下自己的思路。

    (R_{i,l})代表以(l)为线段左端点,包含数从(1)~(i)中所有数字的最近右端点。

    对于(i+1)来说,其所在的位置为(p_{1},p_{2},p_{3},...,p_{k})。这些数将长度为(n)的区间划分为若干部分,如下所示:

    [1, (p_{1})],[(p_{1}+1), (p_{2})],...,[(p_{k}+1),(n)]

    对于每一个区间,其内部所有的 (l) 在从 (R_{i,l}) 转移至 (R_{i+1,l}) 时,式子为(R_{i+1,l}) = (max(R_{i,l}, p_{k}))
    其中,(p_{k})代表其所在区间的右端点。

    特别的,当所在的 (l) 位于最后一个线段中,不可能构成包含数从 (1)~(i) 中所有数字的线段,此时应将 (R_{i+1,l}) 置为无穷大,也就是取不到

    显然在任何情况下 (R_{i,l})单调递增的。最后,将问题转移成了对于每一个区间,找到 (R_{i,l} < p_{k}) 的一段数并将其值赋为 (p_{k}) 。这个操作可以利用线段树进行维护。

    线段树维护过程:

    用结构体存储线段树每个节点的左端点和右端点,当被赋值时,因为时区间同时赋值,因此所在区间的最短线段的长度记为 (val - T[rt].r + 1)

    在查询 (R_{i,l} < p_{k}) 的左端点时尽可能地往左边走,在查询右端点时尽可能地往右边走,如果整个区间内没有符合的情况则跳过赋值。

    AC代码

    #include <bits/stdc++.h>
    
    #define SZ(x) (int)x.size()
    #define pii pair<int, int>
    #define mp make_pair
    #define inf 0x3f3f3f3f
    #define pb push_back
    using namespace std;
    const int MAXN = 2e5 + 5;
    
    int init_val[MAXN];
    
    class SEG {
    public:
        struct node {
            int l, r;
            int val, minn;  // val是维护的右端点,minn是线段长度
        } T[MAXN << 2];
        int lazy[MAXN << 2];
    
        inline void push_up(int rt) {
            T[rt].minn = min(T[rt << 1].minn, T[rt << 1 | 1].minn);
            T[rt].val = min(T[rt << 1].val, T[rt << 1 | 1].val);
        }
    
        void build(int rt, int l, int r) {
            T[rt].l = l, T[rt].r = r;
            if (l == r) {
                T[rt].minn = init_val[l] - r + 1;
                T[rt].val = init_val[l];
                return;
            }
            int mid = (l + r) >> 1;
            build(rt << 1, l, mid), build(rt << 1 | 1, mid + 1, r);
            push_up(rt);
        }
    
        inline void push_down(int rt) {
            if (lazy[rt]) {
                T[rt << 1].val = lazy[rt], T[rt << 1 | 1].val = lazy[rt];
                T[rt << 1].minn = lazy[rt] - T[rt << 1].r + 1, T[rt << 1 | 1].minn = lazy[rt] - T[rt << 1 | 1].r + 1;
                lazy[rt << 1] = lazy[rt], lazy[rt << 1 | 1] = lazy[rt];
                lazy[rt] = 0;
            }
        }
    
        int query_left(int rt, int L, int R, int v) {
            if (T[rt].r < L || T[rt].l > R) return -1;
            if (T[rt].l == T[rt].r) return T[rt].l;
            push_down(rt);
            int ans = -1;
            if (T[rt << 1].val < v) ans = query_left(rt << 1, L, R, v);
            if (ans == -1 && T[rt << 1 | 1].val < v) ans = query_left(rt << 1 | 1, L, R, v);
            return ans;
        }
    
        int query_right(int rt, int L, int R, int v) {
            if (T[rt].r < L || T[rt].l > R) return -1;
            if (T[rt].l == T[rt].r) return T[rt].l;
            push_down(rt);
            int ans = -1;
            if (T[rt << 1 | 1].val < v) ans = query_right(rt << 1 | 1, L, R, v);
            if (ans == -1 && T[rt << 1].val < v) ans = query_right(rt << 1, L, R, v);
            return ans;
        }
    
        void change(int rt, int L, int R, int v) {
            if (L <= T[rt].l && T[rt].r <= R) {
                T[rt].val = v;
                T[rt].minn = v - T[rt].r + 1;
                lazy[rt] = v;
                return;
            }
            push_down(rt);
            int mid = (T[rt].l + T[rt].r) >> 1;
            if (L <= mid) change(rt << 1, L, R, v);
            if (R > mid) change(rt << 1 | 1, L, R, v);
            push_up(rt);
        }
    
    } tree;
    
    int a[MAXN];
    vector<int> vec[MAXN];
    
    int main() {
        int n, m;
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
        for (int i = 1; i <= n; i++) vec[a[i]].pb(i);
    
        int pos = inf;
        for (int i = n; i >= 1; i--) {
            if (a[i] == 1) pos = i;
            init_val[i] = pos;
        }
        tree.build(1, 1, n);
        printf("%d", tree.T[1].minn);   // m = 1
    
        for (int i = 2; i <= m; i++) {
            for (int j = 0; j < SZ(vec[i]); j++) {
                int l, r, p = vec[i][j];
                if (j == 0) { // segment no 1
                    l = 1, r = vec[i][j];
                } else l = vec[i][j - 1] + 1, r = vec[i][j];
                int left = tree.query_left(1, l, r, p);
                int right = tree.query_right(1, l, r, p);
                if (left == -1 && right == -1) {
    
                } else {
                    tree.change(1, left, right, p);
                }
            }
            if (vec[i][SZ(vec[i]) - 1] == n) {}
            else {
                tree.change(1, vec[i][SZ(vec[i]) - 1] + 1, n, inf);   // 忘记+1导致debug了好久
            }
            printf(" %d", tree.T[1].minn);
        }
    }
    

    附上一组样例:

    10 4
    1 1 2 3 1 2 1 4 1 4
    
  • 相关阅读:
    Objective-C-使用NSMutableURLRequest发送POST请求,使用NSJSONSerialization解析JSON字符串
    js showModalDialog打开新的页面给原页面传值问题
    svn2git使用小记
    模拟等待事件row lock waits
    URAL 1994 The Emperor's plan 求组合数 大数用log+exp处理
    struts总结
    URAL 1992 CVS 链表
    android游戏物理引擎开发——粒子系统(三)
    状态模式与上机
    OpenCV——凸包
  • 原文地址:https://www.cnblogs.com/tudouuuuu/p/13878728.html
Copyright © 2011-2022 走看看