来一篇超全题解
数据结构大杂烩
原题连接
题目描述
敌人有 N N N 个工兵营地,编号 1 ∼ N 1∼N 1∼N。
初始时,第 i i i 个营地有 a i a_i ai 个人。
接下来有若干个命令,命令有 4 4 4 种形式:
Add i j
,
i
i
i 和
j
j
j 为正整数,表示第
i
i
i 个营地增加
j
j
j 个人。(
j
j
j 不超过
30
30
30)
Sub i j
,
i
i
i 和
j
j
j 为正整数,表示第
i
i
i 个营地减少
j
j
j 个人。(
j
j
j 不超过
30
30
30)
Query i j
,
i
i
i 和
j
j
j 为正整数
(
i
≤
j
)
(i≤j)
(i≤j),表示询问第
i
i
i 到第
j
j
j 个营地的总人数。
End
,表示结束,此命令只会作为最后一条命令出现。
请你计算每个 Query
的答案。
输入格式
第一行包含整数
T
T
T,表示共有
T
T
T 组测试数据。
每组数据第一行包含一个整数 N N N。
第二行包含 N N N 个整数 a 1 , a 2 , … , a N a1,a2,…,aN a1,a2,…,aN。
接下来若干行,每行包含一条命令,格式如题目所述。
输出格式
对于第
i
i
i 组数据,首先输出一行 Case i:
,然后对于每个 Query
询问,输出一行一个整数,表示询问的段中的总人数。
数据范围
1
≤
T
≤
10
,
1≤T≤10,
1≤T≤10,
1
≤
N
≤
50000
,
1≤N≤50000,
1≤N≤50000,
1
≤
a
i
≤
50
,
1≤ai≤50,
1≤ai≤50,
每组数据最多有
40000
40000
40000 条命令,
保证任何营地的人数都不会减少为负数。
输入样例:
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
暴力 + 快读快写 + 吸氧 T L 90 p t s TL 90pts TL90pts
#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;
}
优雅的暴力永不过时~~
分块 A C AC AC 1194 m s 1194ms 1194ms
O ( m n ) O(m \sqrt{n}) O(mn)
#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;
}
大杀器
线段树 A C AC AC 1868 m s 1868ms 1868ms
O ( m log 2 n ) O(m \log_2{n}) O(mlog2n)
#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;
}
常数稍小的线段树
Z k w Zkw Zkw线段树 A C AC AC 1158 m s 1158ms 1158ms
O ( m log 2 n ) O(m \log_2{n}) O(mlog2n)
#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;
}
树状数组 A C AC AC 890 m s 890ms 890ms
O ( m log 2 n ) O(m \log_2{n}) O(mlog2n)
#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 ( m n ) O(m\sqrt{n}) O(mn)和 O ( m log 2 n ) O(m\log_2{n}) O(mlog2n)的数据结构。只要把模板打熟,以后遇到这样的题就不怕了~~