线段树习题集

线段树

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

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;
}

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ღCauchyོꦿ࿐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值