题集(线段树1 & 离散化模版)
A 敌兵布阵 (HDU - 1166)
题目链接
(线段树 或 树状数组)
线段树模板题
树状数组单点更新和区间查询
线段树代码:
#include <iostream>
#include <cstdio>
#include <string>
using namespace std;
const int M = 50005;
int tree[M << 2], num[M];
void build(int rt, int l, int r) {
if (l == r) {
tree[rt] = num[l];
return;
}
int mid = l + r >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];
}
void update(int rt, int x, int num, int L, int R) {
if (L == R) {
tree[rt] += num;
return;
}
int mid = L + R >> 1;
if (x <= mid) update(rt << 1, x, num, L, mid);
else update(rt << 1 | 1, x, num, mid + 1, R);
tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];
}
int query(int rt, int l, int r, int L, int R) {
if (L > r || R < l) return 0;
if (L >= l && R <= r) return tree[rt];
int mid = L + R >> 1;
int ans = 0;
ans += query(rt << 1, l, r, L, mid);
ans += query(rt << 1 | 1, l, r, mid + 1, R);
return ans;
}
int main() {
int t;
scanf("%d", &t);
int cnt = 1;
while (t--) {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; ++i) scanf("%d", &num[i]);
build(1, 1, n);
printf("Case %d:\n", cnt++);
string str;
while (cin >> str) {
if (str == "End") break;
if (str == "Add") {
int x, num;
scanf("%d%d", &x, &num);
update(1, x, num, 1, n);
}
else if (str == "Sub") {
int x, num;
scanf("%d%d", &x, &num);
update(1, x, -num, 1, n);
}
else if (str == "Query") {
int l, r;
scanf("%d%d", &l, &r);
printf("%d\n", query(1, l, r, 1, n));
}
}
}
}
树状数组代码:
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
using namespace std;
const int M = 50005;
int n;
int num[M], tree[M << 2];
int lowbit(int x) { return x & (-x); }
void update(int x, int num) {
for (int i = x; i <= n; i += lowbit(i)) tree[i] += num;
}
int query(int l, int r) {
int ans1 = 0;
for (int i = r; i; i -= lowbit(i)) ans1 += tree[i];
int ans2 = 0;
for (int i = l - 1; i; i -= lowbit(i)) ans2 += tree[i];
return ans1 - ans2;
}
int main() {
int t;
int cnt = 1;
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
memset(tree, 0, sizeof(tree));
for (int i = 1; i <= n; ++i) {
scanf("%d", &num[i]);
update(i, num[i]);
}
string str;
printf("Case %d:\n", cnt++);
while (cin >> str) {
if (str == "End") break;
if (str == "Add") {
int x, num;
scanf("%d%d", &x, &num);
update(x, num);
}
else if (str == "Sub") {
int x, num;
scanf("%d%d", &x, &num);
update(x, -num);
}
else if (str == "Query") {
int l, r;
scanf("%d%d", &l, &r);
printf("%d\n", query(l, r));
}
}
}
}
B Lost Cows(POJ - 2182)
线段树: 节点为1代表节点编号还未存在,节点为0待变编号存在,从后往前看起
输入样例中: 1 2 1 0 从后往前看
先看0,从[1, n]中找出未被选中过的第1小的数 [1, 2, 3, 4, 5]选中了1 再将1设为被选中 [2, 3, 4, 5]
再看1,从[1, n]中找出未被选中过的第2小的数 [2, 3, 4, 5]选中了3 再将3设为被选中 [2, 4, 5]
再看2,从[1, n]中找出未被选中过的第3小的数[2, 4, 5]选中了5 再将5设为被选中 [2, 4]
再看1, 从[1, n]中找出未被选中过的第2小的数[2, 4]选中了4 再将4设为被选中 [2]
可以以线段树节点编号作为奶牛编号,节点为1设置为未被选中, 节点为0设置为被选中,每次通过单点查询,查询到相应的编号。
树状数组: 思路大致相同,利用二分查找确定个数
线段树代码:
#include <iostream>
#include <cstdio>
using namespace std;
const int M = 100010;
int num[M], ans[M];
int tree[M << 2];
void build(int rt, int l, int r) {
if (l == r) {
tree[rt] = 1;
return;
}
int mid = l + r >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];
}
int query(int rt, int l, int r, int key) {
if (l == r) {
tree[rt] = 0;
return l;
}
int mid = l + r >> 1;
if (tree[rt << 1] >= key) {
int ans = query(rt << 1, l, mid, key);
tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];
return ans;
}
else if (tree[rt << 1] < key) {
int ans = query(rt << 1 | 1, mid + 1, r, key - tree[rt << 1]);
tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];
return ans;
}
}
int main() {
int n;
scanf("%d", &n);
for (int i = 2; i <= n; ++i) scanf("%d", &num[i]);
build(1, 1, n);
for (int i = n; i >= 2; --i) {
ans[i] = query(1, 1, n, num[i] + 1);
}
ans[1] = query(1, 1, n, 1);
for (int i = 1; i <= n; ++i) printf("%d\n", ans[i]);
return 0;
}
树状数组代码:
#include <iostream>
#include <cstdio>
using namespace std;
const int M = 10010;
int n;
int num[M], tree[M << 2], ans[M];
int lowbit(int x) { return x & (-x); }
void update(int x, int num) {
for (int i = x; i <= n; i += lowbit(i)) {
tree[i] += num;
}
}
int sum(int num) {
int ans = 0;
for (int i = num; i >= 1; i -= lowbit(i)) {
ans += tree[i];
}
return ans;
}
int main() {
scanf("%d", &n);
for (int i = 2; i <= n; ++i) scanf("%d", &num[i]);
for (int i = 1; i <= n; ++i) {
update(i, 1);
}
for (int i = n; i >= 2; --i) {
int l = 1, r = n, mid;
while (l < r) {
mid = l + r >> 1;
if (sum(mid) >= num[i] + 1) r = mid;
else l = mid + 1;
}
ans[i] = l;
update(l, -1);
}
int l = 1, r = n, mid;
while (l < r) {
mid = l + r >> 1;
if (sum(mid) >= 1) r = mid;
else l = mid + 1;
}
ans[1] = l;
for (int i = 1; i <= n; ++i) printf("%d\n", ans[i]);
return 0;
}
C Mayor’s posters(POJ - 2528离散化模版)
题目链接
(线段树 + 离散化)
本题因为离散化,所以要开正常线段树双倍的点所以是8倍需要注意
(离散化模版)
线段树节点保存的是颜色,最终查询整个区间的颜色种数,看当前区间的颜色是否被查询过,未被查询过则颜色种数加1
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int M = 10010;
int f[M << 1], ff[M << 1];
int l[M], r[M], tree[M << 3];
bool vis[M << 1];
int find(int x, int r_max) {
int l = 0, r = r_max;
while (l <= r) {
int mid = l + r >> 1;
if (ff[mid] > x) r = mid;
else if (ff[mid] < x) l = mid + 1;
else if (ff[mid] == x) return mid;
}
}
int query_line(int rt, int l, int r, int L, int R) {
if (L > r || R < l) return 0;
if (L >= l && R <= r) {
if (tree[rt]) {
if (!vis[tree[rt]]) {
vis[tree[rt]] = true;
return 1;
}
return 0;
}
}
int ans = 0;
int mid = L + R >> 1;
ans += query_line(rt << 1, l, r, L, mid);
ans += query_line(rt << 1 | 1, l, r, mid + 1, R);
return ans;
}
void pushdown(int rt) {
if (tree[rt]) {
tree[rt << 1] = tree[rt];
tree[rt << 1 | 1] = tree[rt];
tree[rt] = 0;
}
}
void update_line(int rt, int l, int r, int L, int R, int num) {
if (L > r || R < l) return;
if (L >= l && R <= r) {
tree[rt] = num;
return;
}
int mid = L + R >> 1;
pushdown(rt);
update_line(rt << 1, l, r, L, mid, num);
update_line(rt << 1 | 1, l, r, mid + 1, R, num);
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
memset(vis, false, sizeof(vis));
memset(tree, 0, sizeof(tree));
int n;
scanf("%d", &n);
int cnt = 0;
for (int i = 1; i <= n; ++i) {
scanf("%d%d", &l[i], &r[i]);
f[cnt++] = l[i];
f[cnt++] = r[i];
}
sort(f, f + cnt);
ff[1] = f[0];
int tot = 2;
for (int i = 1; i < cnt; ++i) {
if (f[i] != f[i - 1]) {
ff[tot++] = f[i];
}
}
int max_r = tot - 1;
int l_node, r_node;
for (int i = 1; i <= n; ++i) {
l_node = find(l[i], max_r);
r_node = find(r[i], max_r);
update_line(1, l_node, r_node, 1, max_r, i);
}
int ans = query_line(1, 1, max_r, 1, max_r);
printf("%d\n", ans);
}
return 0;
}
浙公网安备 33010602011771号