线段树入门之单点更新

  • 作者:zifeiy
  • 标签:线段树

单点更新 :最最基础的线段树,只更新叶子节点,然后把信息用 push_up(int rt) 这个函数更新上来

HDU1166 敌兵布阵

#include <bits/stdc++.h>
using namespace std;
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
const int maxn = 50050;
int sum[maxn<<2];
inline void push_up(int rt) { sum[rt] = sum[rt<<1] + sum[rt<<1|1]; }
void build(int l, int r, int rt) {
    if (l == r) { cin >> sum[rt]; return; }
    int m = (l + r) >> 1;
    build(lson); build(rson); push_up(rt);
}
void update(int p, int add, int l, int r, int rt) {
    if (l == r) { sum[rt] += add; return; }
    int m = (l + r) >> 1;
    (p <= m) ? update(p, add, lson) : update(p, add, rson);
    push_up(rt);
}
int query(int L, int R, int l, int r, int rt) {
    if (L <= l && r <= R) return sum[rt];
    int m = (l + r) >> 1, res = 0;
    if (L <= m) res += query(L, R, lson);
    if (R > m) res += query(L, R, rson);
    return res;
}
int T, n, a, b; char op[10];
int main() {
    scanf("%d", &T);
    for (int cas = 1; cas <= T; cas ++) {
        printf("Case %d:\n", cas);
        scanf("%d", &n);
        build(1, n, 1);
        while (scanf("%s", op) && op[0] != 'E') {
            scanf("%d%d", &a, &b);
            if (op[0] == 'A') update(a, b, 1, n, 1);
            else if (op[0] == 'S') update(a, -b, 1, n, 1);
            else printf("%d\n", query(a, b, 1, n, 1));
        }
    }
    return 0;
}

HDU1754 I Hate It

#include <bits/stdc++.h>
using namespace std;
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
const int maxn = 200020;
int maxv[maxn<<2];
inline void push_up(int rt) { maxv[rt] = max(maxv[rt<<1], maxv[rt<<1|1]); }
void build(int l, int r, int rt) {
    if (l == r) { scanf("%d", &maxv[rt]); return; }
    int m = (l + r) >> 1;
    build(lson); build(rson); push_up(rt);
}
void update(int p, int val, int l, int r, int rt) {
    if (l == r) { maxv[rt] = val; return; }
    int m = (l + r) >> 1;
    (p <= m) ? update(p, val, lson) : update(p, val, rson);
    push_up(rt);
}
int query(int L, int R, int l, int r, int rt) {
    if (L <= l && r <= R) return maxv[rt];
    int m = (l + r) >> 1, res = 0;
    if (L <= m) res = max(res, query(L, R, lson));
    if (R > m) res = max(res, query(L, R, rson));
    return res;
}
int n, m, a, b; char op[10];
int main() {
    while (~scanf("%d%d", &n, &m)) {
        build(1, n, 1);
        while (m --) {
            scanf("%s%d%d", op, &a, &b);
            if (op[0] == 'U') update(a, b, 1, n, 1);
            else printf("%d\n", query(a, b, 1, n, 1));
        }
    }
    return 0;
}

HDU1394 Minimum Inversion Number

  • 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394
  • 题目大意:给你一个长度为n的数组,你可以选择任意次数将数组的最后一个元素放到数组的最前面的那个位置(每次操作称为一次Inversion),求所有Inversion操作中数组的最小逆序对。
  • 思路:用 \(O(n \times \log n)\) 复杂度求出最初逆序对,就可以用 \(O(1)\) 的复杂度分别递推求出其他解。
  • 线段树功能:
    • update:单点更新;
    • query:区间求和
#include <bits/stdc++.h>
using namespace std;
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
const int maxn = 5050;
int sum[maxn<<2];
inline void push_up(int rt) { sum[rt] = sum[rt<<1] + sum[rt<<1|1]; }
void build(int l, int r, int rt) {
    if (l == r) { sum[rt] = 0; return; }
    int m = (l + r) >> 1;
    build(lson); build(rson); push_up(rt);
}
void add(int p, int l, int r, int rt) {
    if (l == r) { sum[rt] ++; return; }
    int m = (l + r) >> 1;
    (p <= m) ? add(p, lson) : add(p, rson);
    push_up(rt);
}
int query(int L, int R, int l, int r, int rt) {
    if (L <= l && r <= R) return sum[rt];
    int m = (l + r) >> 1, res = 0;
    if (L <= m) res += query(L, R, lson);
    if (R > m) res += query(L, R, rson);
    return res;
}
int n, a[maxn], p[maxn], res, tmp;
int main() {
    while (~scanf("%d", &n)) {
        for (int i = 0; i < n; i ++) {
            cin >> a[i];
            p[ a[i] ] = i;
        }
        build(0, n-1, 1);
        res = 0;
        for (int i = 0; i < n; i ++) {
            res += query(p[i], n-1, 0, n-1, 1);
            add(p[i], 0, n-1, 1);
        }
        tmp = res;
        for (int i = 0; i < n-1; i ++) {
            tmp += (n - 1 - a[i]) - a[i];
            res = min(res, tmp);
        }
        printf("%d\n", res);
    }
    return 0;
}

HDU2795 Billboard

  • 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2795
  • 题意: \(h \times w\) 的黑板,要贴一些一些 \(1 \times L\) 的海报,海报要尽可能往上放,同一高度要尽可能往左放,求每张海报放的位置。
  • 思路:每次找到最左边满足大于等于L的位置,然后减去L
  • 线段树功能:
    • query:区间求最大值的位置(直接把 update 的操作写在 query 里面了)
#include <bits/stdc++.h>
using namespace std;
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
const int maxn = 200020;
int n, h, w, maxv[maxn<<2];
inline void push_up(int rt) { maxv[rt] = max(maxv[rt<<1], maxv[rt<<1|1]); }
void build(int l, int r, int rt) {
    maxv[rt] = w;
    if (l == r) return;
    int m = (l + r) >> 1;
    build(lson); build(rson);
}
int query(int x, int l, int r, int rt) {
    if (l == r) { maxv[rt] -= x; return l; }
    int m = (l + r) >> 1;
    int res = (maxv[rt<<1] >= x) ? query(x, lson) : query(x, rson);
    push_up(rt);
    return res;
}
int main() {
    while (~scanf("%d%d%d", &h, &w, &n)) {
        if (h > n) h = n;
        build(1, h, 1);
        while (n --) {
            int x;
            scanf("%d", &x);
            if (maxv[1] < x) puts("-1");
            else printf("%d\n", query(x, 1, h, 1));
        }
    }
    return 0;
}

练习

原文地址:https://www.cnblogs.com/codedecision/p/11676957.html

时间: 2024-10-11 13:57:17

线段树入门之单点更新的相关文章

hdu 4893 Wow! Such Sequence!(线段树功能:单点更新,区间更新相邻较小斐波那契数)

转载请注明出处:http://blog.csdn.net/u012860063?viewmode=contents 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4893 --------------------------------------------------------------------------------------------------------------------------------------------

POJ2886 Who Gets the Most Candies? 【线段树】+【单点更新】+【模拟】+【反素数】

Who Gets the Most Candies? Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 9416   Accepted: 2868 Case Time Limit: 2000MS Description N children are sitting in a circle to play a game. The children are numbered from 1 to N in clockwise o

HDU2795 Billboard 【线段树】+【单点更新】

Billboard Time Limit: 20000/8000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 9632    Accepted Submission(s): 4286 Problem Description At the entrance to the university, there is a huge rectangular billboard of s

POJ2828 Buy Tickets 【线段树】+【单点更新】+【逆序】

Buy Tickets Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 12296   Accepted: 6071 Description Railway tickets were difficult to buy around the Lunar New Year in China, so we must get up early and join a long queue- The Lunar New Year wa

hdu 1116 敌兵布阵 线段树 区间求和 单点更新

线段树的基本知识可以先google一下,不是很难理解 线段树功能:update:单点增减 query:区间求和 #include <bits/stdc++.h> #define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1 using namespace std; const int MAXN = 50008; int sum[MAXN<<2]; void build(int l, int r, int rt)

HDU(1166),线段树模板,单点更新,区间总和

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1166 第一次做线段树,帆哥的一句话,我记下来了,其实,线段树就是一种处理数据查询和更新的手段. 然后,我的代码风格,是网上的大牛们的辛苦总结,我就套用了.这里,我还是简单说一下线段树,说的不好,主要方便自己复习. 线段树,3个步骤,建树,查询,更新, 建树:到底部就是a[]数组的值,建立左右子树后,向上推根,根为左右子树的值 更新:类似建树,二分,找到单点所在区间,更新该区间,记得上一个区间也要变化

nyoj 119 士兵杀敌(三) 【线段树】【单点更新】

题意:... 策略如题. 思路:我们先假设只求某一区间的最大值,我们只需要利用线段树的模板,只需要初始化和询问的时候小小的修改一下,改成祖先结点储存的不再是子节点的和而是两个子节点之间的最大值,这样我们可以求出最大值了,最小值也是这样求. 注意:因为询问的时候既要求最大值又要求最小值,所以要返回结构体. 代码: #include <stdio.h> #include <string.h> #define M 100005 struct node{ int left, right;

hdu 1754 线段树 水题 单点更新 区间查询

I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 59558    Accepted Submission(s): 23201 Problem Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少.这让很多学生很反感. 不管你喜不喜欢,现在需要你做的是,就是按照老师的要

HDU 1394:Minimum Inversion Number(线段树区间求和单点更新)

http://acm.hdu.edu.cn/showproblem.php?pid=1394 Minimum Inversion Number Problem Description The inversion number of a given number sequence a1, a2, ..., an is the number of pairs (ai, aj) that satisfy i < j and ai > aj. For a given sequence of numbe