zoukankan      html  css  js  c++  java
  • 【洛谷4215】踩气球(线段树)

    题目:

    洛谷4215

    分析:

    感觉思路有点像线段树分治?

    把所有区间插到线段树上。我一开始的想法是修改时给树上一条链上包含的所有熊孩子的值都减(1),然后发现这个单次最坏是(O(m))的,gg

    可以记录每个熊孩子被分成了多少个非零的区间。修改时如果某个区间变成(0)了,那么就给包含该区间的熊孩子的区间数减(1),这样均摊最多有(mlog m)个区间,总复杂度(O(qlog n+mlog n))。和暴力相比,这样做相当于把每个熊孩子最多分的段数从(n)(每个位置一段)变成了(log n)

    代码:

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cctype>
    using namespace std;
    #define _ 0
    
    namespace zyt
    {
        template<typename T>
        inline void read(T &x)
        {
            char c;
            bool f = false;
            x = 0;
            do
                c = getchar();
            while (c != '-' && !isdigit(c));
            if (c == '-')
                f = true, c = getchar();
            do
                x = x * 10 + c - '0', c = getchar();
            while (isdigit(c));
            if (f)
                x = -x;
        }
        template<typename T>
        inline void write(T x)
        {
            static char buf[20];
            char *pos = buf;
            if (x < 0)
                putchar('-'), x = -x;
            do
                *pos++ = x % 10 + '0';
            while (x /= 10);
            while (pos > buf)
                putchar(*--pos);
        }
        const int N = 1e5 + 10, B = 17;
        struct edge
        {
            int to, next;
        }e[N * B];
        int n, m, q, arr[N], seg[N], head[1 << (B + 1) | 11], ecnt, ans;
        inline void add(const int a, const int b)
        {
            e[ecnt] = (edge){b, head[a]}, head[a] = ecnt++;
        }
        namespace Segment_Tree
        {
            struct node
            {
                int sum;
            }tree[1 << (B + 1) | 11];
            inline void update(const int rot)
            {
                tree[rot].sum = tree[rot << 1].sum + tree[rot << 1 | 1].sum;
            }
            void build(const int rot, const int lt, const int rt)
            {
                head[rot] = -1;
                if (lt == rt)
                {
                    tree[rot].sum = arr[lt];
                    return;
                }
                int mid = (lt + rt) >> 1;
                build(rot << 1, lt, mid);
                build(rot << 1 | 1, mid + 1, rt);
                update(rot);
            }
            void insert(const int rot, const int lt, const int rt, const int ls, const int rs, const int id)
            {
                if (ls <= lt && rt <= rs)
                {
                    if (tree[rot].sum)
                        ++seg[id];
                    add(rot, id);
                    return;
                }
                int mid = (lt + rt) >> 1;
                if (ls <= mid)
                    insert(rot << 1, lt, mid, ls, rs, id);
                if (rs > mid)
                    insert(rot << 1 | 1, mid + 1, rt, ls, rs, id);
            }
            void change(const int rot, const int lt, const int rt, const int pos)
            {
                if (lt == rt)
                    --tree[rot].sum;
                else
                {
                    int mid = (lt + rt) >> 1;
                    if (pos <= mid)
                        change(rot << 1, lt, mid, pos);
                    else
                        change(rot << 1 | 1, mid + 1, rt, pos);
                    update(rot);
                }
                if (!tree[rot].sum)
                    for (int i = head[rot]; ~i; i = e[i].next)
                        if (!--seg[e[i].to])
                            ++ans;
            }
        }
        int work()
        {
            using namespace Segment_Tree;
            read(n), read(m);
            for (int i = 1; i <= n; i++)
                read(arr[i]);
            build(1, 1, n);
            for (int i = 1; i <= m; i++)
            {
                int l, r;
                read(l), read(r);
                insert(1, 1, n, l, r, i);
                if (!seg[i])
                    ++ans;
            }
            read(q);
            int lastans = 0;
            while (q--)
            {
                int x;
                read(x);
                x = (x + lastans - 1) % n + 1;
                change(1, 1, n, x);
                write(lastans = ans), putchar('
    ');
            }
            return ~~(0^_^0);
        }
    }
    int main()
    {
        return zyt::work();
    }
    
  • 相关阅读:
    C++中的派生类相关内容,结构体、共同体内容
    window查看端口以及telnet的使用
    java中long型转换为int
    C/C++数组初始化全为0
    linux中的一些指令 find
    bat相关知识
    bat设置开机自启动
    for循环语句及批量创建用户!
    Shell函数!
    case语句!
  • 原文地址:https://www.cnblogs.com/zyt1253679098/p/10117429.html
Copyright © 2011-2022 走看看