0
点赞
收藏
分享

微信扫一扫

Acwing 4339 敌兵布阵

孟佳 2022-03-20 阅读 76
c++

来一篇超全题解

数据结构大杂烩

原题连接

题目描述

敌人有 NN 个工兵营地,编号 1N1∼N

初始时,第 ii 个营地有 aia_i 个人。

接下来有若干个命令,命令有 44 种形式:

Add i jiijj 为正整数,表示第 ii 个营地增加 jj 个人。(jj 不超过 3030
Sub i jiijj 为正整数,表示第 ii 个营地减少 jj 个人。(jj 不超过 3030
Query i jiijj 为正整数ij(i≤j),表示询问第 ii 到第 jj 个营地的总人数。
End,表示结束,此命令只会作为最后一条命令出现。
请你计算每个 Query 的答案。

输入格式
第一行包含整数 TT,表示共有 TT 组测试数据。

每组数据第一行包含一个整数 NN

第二行包含 NN 个整数 a1,a2,,aNa1,a2,…,aN

接下来若干行,每行包含一条命令,格式如题目所述。

输出格式
对于第 ii 组数据,首先输出一行 Case i:,然后对于每个 Query 询问,输出一行一个整数,表示询问的段中的总人数。

数据范围

1T10,1≤T≤10,
1N50000,1≤N≤50000,
1ai50,1≤ai≤50,
每组数据最多有 4000040000 条命令,
保证任何营地的人数都不会减少为负数。

输入样例:

1
10
1 2 3 4 5 6 7 8 9 10
Query 1 3
Add 3 6
Query 2 7
Sub 10 2
Add 6 3
Query 3 10
End

输出样例:

Case 1:
6
33
59

Code

暴力 + 快读快写 + 吸氧 TL90ptsTL 90pts

#include <cstdio>

#pragma GCC target ("avx") 
#pragma GCC optimize (2, 3, "Ofast", "inline", "-ffast-math")

const int N = 5e4 + 10;

int n, a[N];

namespace IO
{
    template <class T> inline void read (T &x) { x = 0; bool f = 0; char ch = getchar (); while (ch < '0' || ch > '9') f |= ch == '-', ch = getchar (); while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar (); x = f ? ~x + 1 : x; }
    template <class T> inline void write (T x) { static char c[20]; unsigned p = 0; if (x < 0) putchar ('-'), x = ~x + 1; if (!x) { putchar ('0'); return ; } while (x) c[++p] = x % 10 ^ 48, x /= 10; while (p) putchar (c[p]), --p; }
    template <class T, class... U> inline void read (T &x, U &...t) { read (x), read (t...); }
    template <class T, class... U> inline void write (T x, U ...t) { write (x), write (t...); }
}

using namespace IO;

int main ()
{
    int _; read (_);
    for (int T = 1; T <= _; ++T)
    {
        read (n);
        for (int i = 1; i <= n; ++i) read (a[i]);
        
        printf ("Case %d:\n", T);
        while (true)
        {
            char opt[5];
            int x, y;
            
            scanf ("%s", opt);
            if (*opt == 'A') read (x, y), a[x] += y;
            if (*opt == 'S') read (x, y), a[x] -= y;
            if (*opt == 'Q')
            {
                read (x, y);
                int res = 0;
                for (int i = x; i <= y; ++i) res += a[i];
                write (res), putchar ('\n');
            }
            if (*opt == 'E') break;
        }
    }
    return 0;
}

优雅的暴力永不过时~~

分块 ACAC 1194ms1194ms

O(mn)O(m \sqrt{n})

#include <cstdio>
#include <cmath>
#include <cstring>

#pragma GCC target ("avx")
#pragma GCC optimize (2, 3, "Ofast", "inline", "-ffast-math")

const int N = 5e4 + 10, M = 230;

int n, m, unit, w[N], pos[N], sum[M];

inline void update (int k, int x)
{
    w[k] += x, sum[pos[k]] += x;
}

inline int query (int l, int r)
{
    int res = 0;
    if (pos[l] == pos[r])
        for (int k = l; k <= r; ++k) res += w[k];
    else
    {
        int i = l, j = r;
        while (pos[i] == pos[l]) res += w[i], ++i;
        while (pos[j] == pos[r]) res += w[j], --j;
        for (int k = pos[i]; k <= pos[j]; ++k) res += sum[k];
    }
    return res;
}

namespace IO
{
    template <class T> inline void read (T &x) { x = 0; bool f = 0; char ch = getchar (); while (ch < '0' || ch > '9') f |= ch == '-', ch = getchar (); while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar (); x = f ? ~x + 1 : x; }
    template <class T> inline void write (T x) { static char c[20]; unsigned p = 0; if (x < 0) putchar ('-'), x = ~x + 1; if (!x) { putchar ('0'); return ; } while (x) c[++p] = x % 10 ^ 48, x /= 10; while (p) putchar (c[p]), --p; }
    template <class T, class... U> inline void read (T &x, U &...t) { read (x), read (t...); }
    template <class T, class... U> inline void write (T x, U ...t) { write (x), write (t...); }
}

using namespace IO;

inline void init ()
{
    unit = sqrt (n);
    for (int i = 1; i <= n; ++i) read (w[i]), sum[pos[i] = i / unit] += w[i];
}

int main ()
{
    int _; read (_);
    
    for (int T = 1; T <= _; ++T)
    {
        memset (sum, 0, sizeof sum);
        
        read (n);
        init ();
        
        printf ("Case %d:\n", T);
        while (true)
        {
            char opt[5];
            int x, y;
            scanf ("%s", opt);
            
            if (*opt == 'A') read (x, y), update (x, y);
            if (*opt == 'S') read (x, y), update (x, -y);
            if (*opt == 'Q') read (x, y), write (query (x, y)), putchar ('\n');
            if (*opt == 'E') break;
        }
    }
    return 0;
}

大杀器

线段树 ACAC 1868ms1868ms

O(mlog2n)O(m \log_2{n})

#include <cstdio>

#pragma GCC target ("avx")
#pragma GCC optimize (2, 3, "Ofast", "inline", "-ffast-math")

const int N = 5e4 + 10;

int n, a[N], tr[N << 2], tag[N << 2];

inline void push_up (int x)
{
    tr[x] = tr[x << 1] + tr[x << 1 | 1];   
}

inline void push_down (int mid, int l, int r, int x)
{
    tr[x << 1] += tag[x] * (mid - l + 1);
    tr[x << 1 | 1] += tag[x] * (r - mid);
    tag[x << 1] += tag[x], tag[x << 1 | 1] += tag[x], tag[x] = 0;
}

inline void build (int l = 1, int r = n, int x = 1)
{
    if (l == r) tr[x] = a[l];
    else
    {
        int mid = l + r >> 1;
        build (l, mid, x << 1), build (mid + 1, r, x << 1 | 1);
        push_up (x);
    }
}

inline void update (int l, int r, int d, int nl = 1, int nr = n, int x = 1)
{
    if (l > nr || r < nl) return ;
    if (l <= nl && r >= nr) tag[x] += d, tr[x] += d * (nr - nl + 1);
    else
    {
        int mid = nl + nr >> 1;
        push_down (mid, nl, nr, x);
        update (l, r, d, nl, mid, x << 1), update (l, r, d, mid + 1, nr, x << 1 | 1);
        push_up (x);
    }
}

inline int query (int l, int r, int nl = 1, int nr = n, int x = 1)
{
    if (l > nr || r < nl) return 0;
    if (l <= nl && r >= nr) return tr[x];
    else
    {
        int mid = nl + nr >> 1;
        push_down (mid, nl, nr, x);
        return query (l, r, nl, mid, x << 1) + query (l, r, mid + 1, nr, x << 1 | 1);
    }
}

namespace IO
{
    template <class T> inline void read (T &x) { x = 0; bool f = 0; char ch = getchar (); while (ch < '0' || ch > '9') f |= ch == '-', ch = getchar (); while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar (); x = f ? ~x + 1 : x; }
    template <class T> inline void write (T x) { static char c[20]; unsigned p = 0; if (x < 0) putchar ('-'), x = ~x + 1; if (!x) { putchar ('0'); return ; } while (x) c[++p] = x % 10 ^ 48, x /= 10; while (p) putchar (c[p]), --p; }
    template <class T, class... U> inline void read (T &x, U &...t) { read (x), read (t...); }
    template <class T, class... U> inline void write (T x, U ...t) { write (x), write (t...); }
}

using namespace IO;

int main ()
{
    int _; read (_);
    
    for (int T = 1; T <= _; ++T)
    {
        read (n);
        for (int i = 1; i <= n; ++i) read (a[i]);
        
        build ();
        printf ("Case %d:\n", T);
        while (true)
        {
            char opt[5];
            int x, y;
            scanf ("%s", opt);
            
            if (*opt == 'A') read (x, y), update (x, x, y);
            if (*opt == 'S') read (x, y), update (x, x, -y);
            if (*opt == 'Q') read (x, y), write (query (x, y)), putchar ('\n');
            if (*opt == 'E') break;
        }
    }
    return 0;
}

常数稍小的线段树

ZkwZkw线段树 ACAC 1158ms1158ms

O(mlog2n)O(m \log_2{n})

#include <cstdio>
#include <cstring>

#pragma GCC target ("avx")
#pragma GCC optimize (2, 3, "Ofast", "inline", "-ffast-math")

const int N = 5e4 + 10;

int n, M, a[N], tr[N << 2], tag[N << 2];

inline void update (int s, int t, int d)
{
    int ln = 0, rn = 0, nn = 1;
    for (s += M - 1, t += M + 1; s ^ t ^ 1; s >>= 1, t >>= 1, nn <<= 1)
    {
        tr[s] += d * ln, tr[t] += d * rn;
        if (~s & 1) tag[s ^ 1] += d, tr[s ^ 1] += d * nn, ln += nn;
        if (t & 1) tag[t ^ 1] += d, tr[t ^ 1] += d * nn, rn += nn;
    }
    for (; s; s >>= 1, t >>= 1) tr[s] += d * ln, tr[t] += d * rn;
}

inline int query (int s, int t)
{
    int ans = 0, ln = 0, rn = 0, nn = 1;
    for (s += M - 1, t += M + 1; s ^ t ^ 1; s >>= 1, t >>= 1, nn <<= 1)
    {
        if (tag[s]) ans += tag[s] * ln;
        if (tag[t]) ans += tag[t] * rn;
        if (~s & 1) ans += tr[s ^ 1], ln += nn;
        if (t & 1) ans += tr[t ^ 1], rn += nn;
    }
    for (; s; s >>= 1, t >>= 1) ans += tag[s] * ln, ans += tag[t] * rn;
    return ans;
}

namespace IO
{
    template <class T> inline void read (T &x) { x = 0; bool f = 0; char ch = getchar (); while (ch < '0' || ch > '9') f |= ch == '-', ch = getchar (); while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar (); x = f ? ~x + 1 : x; }
    template <class T> inline void write (T x) { static char c[20]; unsigned p = 0; if (x < 0) putchar ('-'), x = ~x + 1; if (!x) { putchar ('0'); return ; } while (x) c[++p] = x % 10 ^ 48, x /= 10; while (p) putchar (c[p]), --p; }
    template <class T, class... U> inline void read (T &x, U &...t) { read (x), read (t...); }
    template <class T, class... U> inline void write (T x, U ...t) { write (x), write (t...); }
}

using namespace IO;

inline void init ()
{
    M = 1;
    while (M <= n + 1) M <<= 1;
    for (int i = 1; i <= n; ++i) read (tr[M + i]);
    for (int i = M - 1; i; --i) tr[i] = tr[i << 1] + tr[i << 1 | 1];
}

int main ()
{
    int _; read (_);
    
    for (int T = 1; T <= _; ++T)
    {
        read (n);
        init ();
        
        printf ("Case %d:\n", T);
        while (true)
        {
            char opt[5];
            int x, y;
            
            scanf ("%s", opt);
            if (*opt == 'A') read (x, y), update (x, x, y);
            if (*opt == 'S') read (x, y), update (x, x, -y);
            if (*opt == 'Q') read (x, y), write (query (x, y)), putchar ('\n');
            if (*opt == 'E') break;
        }
    }
    return 0;
}

树状数组 ACAC 890ms890ms

O(mlog2n)O(m \log_2{n})

#include <cstdio>
#include <cstring>

#pragma GCC target ("avx")
#pragma GCC optimize (2, 3, "Ofast", "inline", "-ffast-math")

#define lowbit(x) ((x) & ~(x) + 1)

const int N = 5e4 + 10;

int n, tr[N];

inline void update (int k, int x)
{
    while (k <= n) tr[k] += x, k += lowbit (k);
}

inline int query (int k)
{
    int ans = 0;
    while (k) ans += tr[k], k -= lowbit (k);
    return ans;
}

namespace IO
{
    template <class T> inline void read (T &x) { x = 0; bool f = 0; char ch = getchar (); while (ch < '0' || ch > '9') f |= ch == '-', ch = getchar (); while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar (); x = f ? ~x + 1 : x; }
    template <class T> inline void write (T x) { static char c[20]; unsigned p = 0; if (x < 0) putchar ('-'), x = ~x + 1; if (!x) { putchar ('0'); return ; } while (x) c[++p] = x % 10 ^ 48, x /= 10; while (p) putchar (c[p]), --p; }
    template <class T, class... U> inline void read (T &x, U &...t) { read (x), read (t...); }
    template <class T, class... U> inline void write (T x, U ...t) { write (x), write (t...); }
}

using namespace IO;

int main ()
{
    int _; read (_);
    
    for (int T = 1; T <= _; ++T)
    {
        memset (tr, 0, sizeof tr);
        
        read (n);
        for (int i = 1, x; i <= n; ++i)
        {
            read (x), tr[i] += x;
            if (i + lowbit (i) <= n) tr[i + lowbit (i)] += tr[i];
        }
        
        printf ("Case %d:\n", T);
        while (true)
        {
            char opt[5];
            int x, y;
            scanf ("%s", opt);
            
            if (*opt == 'A') read (x, y), update (x, y);
            if (*opt == 'S') read (x, y), update (x, -y);
            if (*opt == 'Q') read (x, y), write (query (y) - query (x - 1)), putchar ('\n');
            if (*opt == 'E') break;
        }
    }
    return 0;
}

总结:

想题目中这样的数据范围,暴力一般都是过不了的,我们自然而然地就想到了上述的这些O(mn)O(m\sqrt{n})O(mlog2n)O(m\log_2{n})的数据结构。只要把模板打熟,以后遇到这样的题就不怕了~~

制作不易,请一键三连~~

举报

相关推荐

0 条评论