线段树习题集

简介: 笔记

线段树


慢慢更新,之后加上思路解析等~~~~

1. 签到快签道

传送门

  • 线段树维护:区间的最小值
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
#define ls u<<1
#define rs u<<1|1
struct node {
  int l, r;
  int v;
} tr[N << 2];
int n, q;
int a[N];
void pushup(int u) {
  tr[u].v = min(tr[ls].v, tr[rs].v);
}
void build(int u, int l, int r) {
  tr[u] = {l, r};
  if(l == r) { tr[u].v = a[l]; return ; }
  int mid = l + r >> 1;
  build(ls, l, mid), build(rs, mid + 1, r);
  pushup(u);
}
int query(int u, int l, int r) {
  if(tr[u].l >= l && tr[u].r <= r) return tr[u].v;
  int mid = tr[u].l + tr[u].r >> 1;
  int ans = 0x7fffffff;
  if(l <= mid) ans = min(ans, query(ls, l, r));
  if(r > mid) ans = min(ans, query(rs, l, r));
  return ans;
}
int main() {
  cin >> n >> q;
  for (int i = 1; i <= n; i++) cin >> a[i];
  build(1, 1, n);
  while(q--) {
    int l, r;
    cin >> l >> r;
    int res = 0x7fffffff;
    if(l != 1) res = query(1, 1, l - 1);
    if(r != n) res = min(res, query(1, r + 1, n));
    cout << res << endl;
  }
  return 0;
}

2. XOR的艺术

传送门


线段树维护:区间的 1 {1}1 的个数

#include <bits/stdc++.h>
using namespace std;
const int N = 200010;
#define ls u<<1
#define rs u<<1|1
struct node {
  int l, r;
  int v, add;
} tr[N << 2];
int a[N];
void pushup(int u) {
  tr[u].v = tr[ls].v + tr[rs].v;
}
void pushdown(int u) {
  if(tr[u].add) {
    tr[u].add ^= 1;
    tr[ls].add ^= 1, tr[rs].add ^= 1;
    tr[ls].v = (tr[ls].r - tr[ls].l + 1) - tr[ls].v;
    tr[rs].v = (tr[rs].r - tr[rs].l + 1) - tr[rs].v;
  }
}
void build(int u, int l, int r) {
  tr[u] = {l, r};
  if(l == r) { tr[u].v = a[l] == 1 ? 1 : 0; return ; }
  int mid = l + r >> 1;
  build(ls, l, mid), build(rs, mid + 1, r);
  pushup(u);
}
int query(int u, int l, int r) {
  if(tr[u].l >= l && tr[u].r <= r) return tr[u].v;
  int mid = tr[u].l + tr[u].r >> 1;
  pushdown(u);
  int ans = 0;
  if(l <= mid) ans = query(ls, l, r);
  if(r > mid) ans += query(rs, l, r);
  return ans;
}
void modify(int u, int l, int r) {
  if(tr[u].l >= l && tr[u].r <= r) {
    tr[u].add ^= 1;
    tr[u].v = (tr[u].r - tr[u].l + 1) - tr[u].v;
    return ;
  }
  pushdown(u);
  int mid = tr[u].l + tr[u].r >> 1;
  if(l <= mid) modify(ls, l, r);
  if(r > mid) modify(rs, l, r);
  pushup(u);
}
int main() {   
    int n, m, p, l, r;
    cin >> n >> m;
    string s; cin >> s;
  for(int i = 0; i < n; i++) a[i + 1] = s[i] - '0';
  build(1, 1, n);
  for(int i = 1; i <= m; i++) {
    cin >> p >> l >> r;
    if(p == 0)
      modify(1, l, r);
    if(p == 1)
      cout << query(1, l, r) << endl; 
  }
    return 0;
}

3. 魔法学院(easy version)

传送门

  • 线段树维护:区间的最大值,区间推平。
#include <bits/stdc++.h>
using namespace std;
const int N = 200010;
#define ls u<<1
#define rs u<<1|1
struct Node {
  int l, r, c;
  bool operator<(const Node& A) const {
    return c < A.c;
  }
} op[N];
struct node {
  int l, r;
  int v;
} tr[N << 2];
int n, q, l, r, c;
string s;
void pushdown(int u) {
  tr[ls].v = max(tr[ls].v, tr[u].v);
  tr[rs].v = max(tr[rs].v, tr[u].v);
}
void build(int u, int l, int r) {
  tr[u] = {l, r};
  if(l == r) { tr[u].v = s[l]; return ; }
  int mid = l + r >> 1;
  build(ls, l, mid), build(rs, mid + 1, r);
}
int query(int u, int x) {
  if(tr[u].l >= x && tr[u].r <= x) return tr[u].v;
  int mid = tr[u].l + tr[u].r >> 1;
  pushdown(u);
  int res = 0;
  if(x <= mid) return query(ls, x);
  return query(rs, x);
}
void modify(int u, int l, int r, int c) {
  if(tr[u].l >= l && tr[u].r <= r) {
    tr[u].v = max(tr[u].v, c);
    return ;
  }
  int mid = tr[u].l + tr[u].r >> 1;
  pushdown(u);
  if(l <= mid) modify(ls, l, r, c);
  if(r > mid) modify(rs, l, r, c);
}
int main() {
  cin >> n >> q;
  cin >> s; s = '#' + s;
  for (int i = 0; i < q; i++) {
    cin >> op[i].l >> op[i].r;
    char c; cin >> c;
    op[i].c = c;
  }
  sort(op, op + q);
  build(1, 1, n);
  for (int i = 0; i < q; i++) modify(1, op[i].l, op[i].r, op[i].c);
  int res = 0;
  for (int i = 1; i <= n; i++) {
    res += query(1, i);
  }
  cout << res << endl;
    return 0;
}
#include <bits/stdc++.h>
using namespace std;
const int N = 10000010;
char s[N];
int a[N];
int n, m;
vector<pair<int, int>> q[127];
int fa[N];
int find(int x) {
    return fa[x] = fa[x] == x ? x : find(fa[x]);
}
int main() {
    scanf("%d%d", &n, &m);
    scanf("%s", s + 1);
    for (int i = 0; i <= n; i++) fa[i] = i;
    int l, r;
    char c;
    while(m--) {
        scanf("%d%d %c", &l, &r, &c);
        q[c].push_back({l, r});
    }
    for (int i = 126; i >= 33; i--) {
        for (int j = 0; j < q[i].size(); j++) {
            l = q[i][j].first, r = q[i][j].second;
            for (int k = find(r); k >= l; k = find(k)) {
                s[k] = max(s[k], (char)i);
                fa[k] = find(k - 1);
            }
        }
    }
    long long ans = 0;
    for (int i = 1; i <= n; i++) ans += s[i];
    printf("%d\n", ans);
    return 0;
}

4. E - Meaningful Mean

传送门

  • 线段树维护:区间值之和。
#include <bits/stdc++.h>
using namespace std;
#define ls u<<1
#define rs u<<1|1
#define int long long
const int N = 250010;
struct node {
  int l, r;
  int v;
} tr[N << 2];
int n, k, a[N], b[N];
void pushup(int u) {
  tr[u].v = tr[ls].v + tr[rs].v;
}
void build(int u, int l, int r) {
  tr[u] = {l, r};
  if(l == r) return ;
  int mid = l + r >> 1;
  build(ls, l, mid), build(rs, mid + 1, r);
}
int query(int u, int l, int r) {
  if(tr[u].l >= l && tr[u].r <= r) return tr[u].v;
  int mid = tr[u].l + tr[u].r >> 1;
  int ans = 0;
  if(l <= mid) ans = query(ls, l, r);
  if(r > mid) ans += query(rs, l, r);
  return ans;
}
void modify(int u, int x, int v) {
  if(tr[u].l >= x && tr[u].r <= x) {
    tr[u].v += v;
    return ;
  }
  int mid = tr[u].l + tr[u].r >> 1;
  if(x <= mid) modify(ls, x, v);
  else modify(rs, x, v);
  pushup(u);
}
signed main() {
  cin >> n >> k;
  for (int i = 1; i <= n; i++) cin >> a[i], a[i] -= k;
  a[0] -= k;
  for (int i = 1; i <= n; i++) a[i] += a[i - 1], b[i] = a[i];
  b[0] = a[0];
  sort(a, a + 1 + n);
  for (int i = 0; i <= n; i++)
    b[i] = lower_bound(a, a + 1 + n, b[i]) - a;
  build(1, 0, n);
  int res = 0;
  // sum(r) >= sum(l - 1)
  for (int i = 1; i <= n; i++) {
    modify(1, b[i - 1], 1);
    res += query(1, 0, b[i]);
  }
  cout << res << endl;
    return 0;
}

5. 干饭得插队

传送门

  • 线段树维护:区间值之和。
#include <bits/stdc++.h>
using namespace std;
#define ls u<<1
#define rs u<<1|1
const int N = 1000010;
struct node {
  int l, r;
  int v;
} tr[N << 2];
struct Node {
  int id, val;
} a[N];
int n, k;
int ans[N];
int len(int u) {
  return tr[u].r - tr[u].l + 1;
}
void pushup(int u) {
  tr[u].v = tr[ls].v + tr[rs].v;
}
void build(int u, int l, int r) {
  tr[u] = {l, r};
  if(l == r) return ;
  int mid = l + r >> 1;
  build(ls, l, mid), build(rs, mid + 1, r);
}
void modify(int u, int x, int v) {
  if(tr[u].l == tr[u].r) {
    tr[u].v += 1;
    ans[tr[u].l] = v;
    return ;
  }
  if(x <= len(ls) - tr[ls].v) modify(ls, x, v);
  else modify(rs, x + tr[ls].v - len(ls), v);
  pushup(u);
}
int main() {
  cin >> n;
  for (int i = 1; i <= n; i++) cin >> a[i].id >> a[i].val;
  build(1, 1, n);
  for (int i = n; i >= 1; i--) {
    int id = a[i].id + 1, val = a[i].val;
    modify(1, id, val);
  }
  for (int i = 1; i <= n; i++) cout << ans[i] << ' ';
    return 0;
}

6. 割韭菜

待补!!!

https://ac.nowcoder.com/acm/contest/30825/A


7. Rooks Defenders

传送门

  • 板子,区间修改,区间查询
#include <bits/stdc++.h>
using namespace std;
#define ls u<<1
#define rs u<<1|1
#define int long long
const int N = 250000;
struct node{
  int l, r;
  int sum, add;
}tr[N << 2];
int a[N];
int n, m;
void pushup(int u) {
  tr[u].sum = tr[ls].sum + tr[rs].sum;
}
int len(int u) {
  return tr[u].r - tr[u].l + 1;
}
void pushdown(int u) {
  if(tr[u].add) {
    tr[ls].sum = tr[u].add * len(ls);
    tr[rs].sum = tr[u].add * len(rs);
    tr[ls].add = tr[u].add;
    tr[rs].add = tr[u].add;
    tr[u].add = 0;
  }
}
void build(int u, int l, int r) {
  tr[u] = {l, r, 0, 0};
  if(l == r) { tr[u].sum = a[l]; tr[u].add = 0; return ;}
  int mid = l + r >> 1;
  build(ls, l, mid), build(rs, mid + 1, r);
  pushup(u);
}
void modify(int u, int l, int r, int x) {
  if (tr[u].l >= l && tr[u].r <= r) {
    tr[u].sum = len(u) * x;
    tr[u].add = x;
    return ;
  }
  pushdown(u);
  int mid = tr[u].l + tr[u].r >> 1;
  if(l <= mid) modify(ls, l, r, x);
  if(r > mid) modify(rs, l, r, x);
  pushup(u);
}
int query(int u, int l, int r) {
  if(tr[u].l >= l && tr[u].r <= r) { return tr[u].sum; }
  int mid = tr[u].l + tr[u].r >> 1;
  int v = 0;
  pushdown(u);
  if(l <= mid) v = query(ls, l, r);
  if(r > mid) v += query(rs, l, r);
  return v;
}
signed main() {
  cin >> n >> m;
  for (int i = 1; i <= n; i++) cin >> a[i];
  build(1, 1, n);
  int op, x, v;
  while(m--) {
    cin >> op;
    if(op == 1) {
      cin >> x >> v;
      modify(1, x, x, v);
    } else {
      cin >> x;
      modify(1, 1, n, x);
    }
    cout << query(1, 1, n) << endl;
  }
  return 0;
}
相关文章
|
7月前
|
算法 Android开发
LeetCode 周赛上分之旅 #48 一道简单的树上动态规划问题
学习数据结构与算法的关键在于掌握问题背后的算法思维框架,你的思考越抽象,它能覆盖的问题域就越广,理解难度也更复杂。在这个专栏里,小彭与你分享每场 LeetCode 周赛的解题报告,一起体会上分之旅。
45 1
|
5天前
|
算法
再探二分法
【2月更文挑战第5天】
32 3
|
7月前
|
机器学习/深度学习 存储 C++
[蓝桥杯] 树状数组与线段树问题(C/C++)
[蓝桥杯] 树状数组与线段树问题(C/C++)
55 0
线段树(线段树入门笔记)
线段树(线段树入门笔记)
|
10月前
|
算法
食物链问题(并查集)
食物链问题(并查集)
67 0
|
10月前
|
算法
【开卷数据结构 】图的遍历,广搜和深搜(基础)
【开卷数据结构 】图的遍历,广搜和深搜(基础)
65 0
|
uml
牛客 小乐乐学数学(扫描线+树状数组)
牛客 小乐乐学数学(扫描线+树状数组)
75 0
UPC-探险(线段树+二分)
UPC-探险(线段树+二分)
59 0
HDU-致命武器(线段树)
HDU-致命武器(线段树)
74 0
|
算法 C++
蓝桥杯第十三讲--树状数组与线段树【习题】
蓝桥杯第十三讲--树状数组与线段树【习题】
138 0
蓝桥杯第十三讲--树状数组与线段树【习题】