树状数组

241. 楼兰图腾

题意:求组成“v”型和“^”型的坐标三元组。

  树状数组优化,从前往后和从后往前两次扫描,比如“v”型,从前往后求比 a[i] 大的个数和从后往前求比 a[i] 大的个数,相乘即得结果。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <bits/stdc++.h>
using namespace std;

#define debug(x) cout << #x << " is " << x << endl
typedef long long ll;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 5;

int n;
int a[N], c[N];
int gre[N], low[N];

int lowbit(int x) { return x & -x; }

void add(int x, int v) {
    for (; x <= n; x += lowbit(x)) c[x] += v;
}

int sum(int x) {
    int res = 0;
    for (; x; x -= lowbit(x)) res += c[x];
    return res;
}

int main() 
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> n;
    for (int i = 1; i <= n; ++i) cin >> a[i];
    for (int i = 1; i <= n; ++i) {
        int x = a[i];
        gre[i] = sum(n) - sum(x);
        low[i] = sum(x - 1);
        add(x, 1);
    }
    memset(c, 0, sizeof(c));
    ll ans1 = 0, ans2 = 0;
    for (int i = n; i; --i) {
        int x = a[i];
        ans1 += 1ll * gre[i] * (sum(n) - sum(x));
        ans2 += 1ll * low[i] * sum(x - 1);
        add(x, 1);
    }
    cout << ans1 << ' ' << ans2 << '\n';
    return 0;
}

242. 一个简单的整数问题

题意:区间修改,单点查询模板题。

  利用差分数组,将区间修改转化成单点修改,单点查询转化成区间查询。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <bits/stdc++.h>
using namespace std;

#define debug(x) cout << #x << " is " << x << endl
typedef long long ll;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const int N = 1e5 + 5;

int n, m;
int a[N], c[N];

int lowbit(int x) { return x & -x; }

void add(int x, int v) {
    for (; x <= n; x += lowbit(x)) c[x] += v;
}

ll sum(int x) {
    ll res = 0;
    for (; x; x -= lowbit(x)) res += c[x];
    return res;
}

int main() 
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) cin >> a[i];
    for (int i = 1; i <= n; ++i) add(i, a[i] - a[i-1]);
    char op;
    int x, y, z;
    while (m--) {
        cin >> op >> x;
        if (op == 'C') {
            cin >> y >> z;
            add(x, z); add(y + 1, -z);
        }
        else if (op == 'Q') {
            cout << sum(x) << '\n';
        }
    }
    return 0;
}

线段树

1275. 最大数

题意:改了叙述方式的模板题,两种操作,向序列添加数,求区间最大值。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <bits/stdc++.h>
using namespace std;

#define debug(x) cout << #x << " is " << x << endl
typedef long long ll;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 5;

struct Node {
    int l, r, dat;
}tr[N<<2];

int m, p;

void push_up(int u) {
    tr[u].dat = max(tr[u<<1].dat, tr[u<<1|1].dat);
}

void build(int u, int l, int r) {
    tr[u].l = l, tr[u].r = r;
    if (l == r) return;
    int mid = (l + r) >> 1;
    build(u<<1, l, mid);
    build(u<<1|1, mid + 1, r);
}

void update(int u, int x, int v) {
    if (tr[u].l == tr[u].r) { tr[u].dat = v; return; }
    int mid = (tr[u].l + tr[u].r) >> 1;
    if (x <= mid) update(u<<1, x, v);
    else update(u<<1|1, x, v);
    push_up(u);
}

int query(int u, int l, int r) {
    if (tr[u].l >= l && tr[u].r <= r) return tr[u].dat;
    int mid = (tr[u].l + tr[u].r) >> 1;
    int res = 0;
    if (l <= mid) res = query(u<<1, l, r);
    if (r > mid) res = max(res, query(u<<1|1, l, r));
    return res;
}

int main() 
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> m >> p;
    build(1, 1, m);
    char op;
    int x, last = 0, n = 0;
    while (m--) {
        cin >> op >> x;
        if (op == 
            'Q') {
            last = query(1, n - x + 1, n);
            cout << last << '\n';
        }
        else if (op == 'A') {
            update(1, n + 1, (1ll * last + x) % p);
            n++;
        }
    }
    return 0;
}

245. 你能回答这些问题吗

题意:长度为 $n(n\le5e5)$ 的数列 $a$,和 $m$ 条指令,每条指令形如:

  1. 1 x y,求区间 $[x,y]$ 的最大连续子段和

  2. 2 x y,把 $a[x]$ 改成 y

对第一个查询输出答案。

  

AC自动机

1282. 搜索关键词