线段树相关练习

xiaoxiao2025-10-07  25

任重而道远

AC代码:

#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> using namespace std; typedef long long ll; const int N = 1e5 + 5; struct Node { ll val, maxn; Node *ls, *rs; void update (void) { val = ls -> val + rs -> val; maxn = max (ls -> maxn, rs -> maxn); } }pool[N << 1], *tail = pool, *root, *zero; ll n, m; ll a[N]; ll read () { ll x = 0, jud = 1; char c = getchar (); while (c < '0' || c > '9') {if (c == '-') jud = -1; c = getchar ();} while (c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar ();} return x * jud; } void init () { zero = ++tail; zero -> ls = zero -> rs = zero; zero -> val = zero -> maxn = 0; } Node *newnode () { Node *nd = ++tail; nd -> ls = nd -> rs = zero; nd -> val = nd -> maxn = 0; return nd; } Node *build (ll l, ll r) { Node *nd = newnode (); if (l == r) { nd -> val = a[l]; nd -> maxn = a[l]; } else { int mid = l + r >> 1; nd -> ls = build (l, mid); nd -> rs = build (mid + 1, r); nd -> update (); } return nd; } void modify (Node *nd, ll l, ll r, ll o, ll val) { if (l == r) { nd -> val = val; nd -> maxn = val; } else { int mid = l + r >> 1; if (o <= mid) modify (nd -> ls, l, mid, o, val); else modify (nd -> rs, mid + 1, r, o, val); nd -> update (); } } void modify (Node *nd, ll l, ll r, ll L, ll R, ll Mod) { if (nd -> maxn < Mod) return; if (l == r) { nd -> val %= Mod; nd -> maxn = nd -> val; } else { int mid = l + r >> 1; if (L <= mid) modify (nd -> ls, l, mid, L, R, Mod); if (R > mid) modify (nd -> rs, mid + 1, r, L, R, Mod); nd -> update (); } } ll query (Node *nd, ll l, ll r, ll L, ll R) { if (L <= l && R >= r) return nd -> val; int mid = l + r >> 1; ll rt = 0; if (L <= mid) rt += query (nd -> ls, l, mid, L, R); if (mid < R) rt += query (nd -> rs, mid + 1, r, L, R); return rt; } int main () { freopen ("mod.in", "r", stdin); freopen ("mod.out", "w", stdout); n = read (), m = read (), init (); for (int i = 1; i <= n; i++) a[i] = read (); root = build (1, n); while (m--) { ll opt = read (); if (opt == 1) { ll l = read (), r = read (); printf ("%lld\n", query (root, 1, n, l, r)); } else if (opt == 2) { ll l = read (), r = read (), x = read (); modify (root, 1, n, l, r, x); } else { ll k = read (), y = read (); modify (root, 1, n, k, y); } } return 0; }

描述

给一个长为N的数列,有M次操作,每次操作时以下三种之一:

(1)修改数列中的一个数

(2)求数列中某连续一段所有数的两两乘积的和 mod 1000000007

(3)求数列中某连续一段所有相邻两数乘积的和 mod 1000000007

输入

第一行两个正整数N和M。 第二行N的整数表示这个数列。 接下来M行,每行开头是一个字符,若该字符为'M',则表示一个修改操作,接下来两个整数x和y,表示把x位置的值修改为y;若该字符为'Q',则表示一个询问操作,接下来两个整数x和y,表示对[x,y]区间做2号询问;若该字符为'A',则表示一个询问操作,接下来两个整数x和y,表示对[x,y]区间做3号询问。

输出

对每一个询问操作单独输出一行,表示答案。

AC代码:

#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> using namespace std; typedef long long ll; const int N = 1e5 + 5, Mod = 1e9 + 7; struct Node { ll val, sum, tot, lf, rg; Node *ls, *rs; void update (void) { sum = (ls -> sum + rs -> sum) % Mod; tot = (ls -> sum * rs -> sum % Mod + ls -> tot + rs -> tot) % Mod; lf = ls -> lf, rg = rs -> rg; val = ((ls -> val + rs -> val + ls -> rg * rs -> lf % Mod) % Mod + Mod) % Mod; } }pool[N << 1], *tail = pool, *root, *zero; struct Point {ll sum, tot;}; ll n, m, x, y; ll a[N]; void init () { zero = ++tail; zero -> ls = zero -> rs = zero; zero -> val = zero -> sum = zero -> lf = zero -> rg = 0; } Node *newnode () { Node *nd = ++tail; nd -> ls = nd -> rs = zero; nd -> val = nd -> sum = nd -> lf = nd -> rg = 0; return nd; } Node *build (int l, int r) { Node *nd = newnode (); if (l == r) { nd -> val = 0; nd -> sum = nd -> lf = nd -> rg = (a[l] % Mod + Mod) % Mod; } else { int mid = l + r >> 1; nd -> ls = build (l, mid); nd -> rs = build (mid + 1, r); nd -> update (); } return nd; } void modify (Node *nd, int l, int r, int o, int val) { if (l == r) { nd -> sum = nd -> lf = nd -> rg = (val % Mod + Mod) % Mod; } else { int mid = l + r >> 1; if (o <= mid) modify (nd -> ls, l, mid, o, val); else modify (nd -> rs, mid + 1, r, o, val); nd -> update (); } } Point query_1 (Node *nd, int l, int r, int L, int R) { if (L <= l && R >= r) return (Point) {nd -> sum, nd -> tot}; int mid = l + r >> 1, ok1 = 0, ok2 = 0; Point p1, p2; if (L <= mid) { p1 = query_1 (nd -> ls, l, mid, L, R); ok1 = 1; } if (R > mid) { p2 = query_1 (nd -> rs, mid + 1, r, L, R); ok2 = 1; } if (ok1 && ok2) return (Point) {((p1.sum + p2.sum) % Mod + Mod) % Mod, ((p1.sum * p2.sum % Mod + p1.tot + p2.tot) % Mod + Mod) % Mod}; else if (ok1) return p1; else return p2; } ll query_2 (Node *nd, int l, int r, int L, int R) { if (L <= l && R >= r) return nd -> val; int mid = l + r >> 1, ok1 = 0, ok2 = 0; ll sww = 0; if (L <= mid) { sww = ((sww + query_2 (nd -> ls, l, mid, L, R)) % Mod + Mod) % Mod; ok1 = 1; } if (R > mid) { sww = ((sww + query_2 (nd -> rs, mid + 1, r, L, R)) % Mod + Mod) % Mod; ok2 = 1; } if (ok1 && ok2) sww = ((sww + nd -> ls -> rg * nd -> rs -> lf) % Mod + Mod) % Mod; return sww; } int main () { init (); scanf ("%lld%lld", &n, &m); for (int i = 1; i <= n; i++) scanf ("%lld", &a[i]); root = build (1, n); while (m--) { char opt = getchar(); while (opt != 'Q' && opt != 'A' && opt != 'M') opt = getchar(); scanf ("%lld%lld", &x, &y); if (opt == 'M') { modify (root, 1, n, x, y); } else if (opt == 'Q') { printf ("%lld\n", query_1 (root, 1, n, x, y).tot); } else { printf ("%lld\n", query_2 (root, 1, n, x, y)); } } return 0; }

描述

给一个长为N的数列,有M次操作,每次操作是以下两种之一:

(1)修改数列中的一个数

(2)求数列中某位置在某次操作后的值

输入

第一行两个正整数N和M。 第二行N个整数表示这个数列。 接下来M行,每行开头是一个字符,若该字符为'M',则表示一个修改操作,接下来两个整数x和y,表示把x位置的值修改为y;若该字符为'Q',则表示一个询问操作,接下来两个整数x和y,表示求x位置在第y次操作后的值。

输出

对每一个询问操作单独输出一行,表示答案。

AC代码:

#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> using namespace std; const int N = 1e5 + 5; struct Node { int val; Node *ls, *rs; }pool[N * 20], *tail = pool, *root[N]; int n, m, x, y, a[N]; char opt[10]; Node *build (int l, int r) { Node *nd = ++tail; if (l == r) { nd -> val = a[l]; } else { int mid = l + r >> 1; nd -> ls = build (l, mid); nd -> rs = build (mid + 1, r); } return nd; } Node *modify (Node *rt, int l, int r, int o, int val) { Node *nd = ++tail; if (l == r) { nd -> val = val; } else { int mid = l + r >> 1; if (o <= mid) { nd -> ls = modify (rt -> ls, l, mid, o, val); nd -> rs = rt -> rs; } else { nd -> ls = rt -> ls; nd -> rs = modify (rt -> rs, mid + 1, r, o, val); } } return nd; } int query (Node *nd, int l, int r, int o) { if (l == r) return nd -> val; int mid = l + r >> 1; if (o <= mid) return query (nd -> ls, l, mid, o); else return query (nd -> rs, mid + 1, r, o); } int main () { scanf ("%d%d", &n, &m); for (int i = 1; i <= n; i++) scanf ("%d", &a[i]); root[0] = build (1, n); for (int i = 1; i <= m; i++) { scanf ("%s", opt); scanf ("%d%d", &x, &y); if (opt[0] == 'M') { root[i] = modify (root[i - 1], 1, n, x, y); } else { printf ("%d\n", query (root[y], 1, n, x)); root[i] = root[i - 1]; } } return 0; }

描述

给一个空数列,有M次操作,每次操作是以下三种之一:

(1)在数列后加一个数

(2)求数列中某位置的值

(3)撤销掉最后进行的若干次操作(1和3)

输入

第一行一个正整数M。 接下来M行,每行开头是一个字符,若该字符为'A',则表示一个加数操作,接下来一个整数x,表示在数列后加一个整数x;若该字符为'Q',则表示一个询问操作,接下来一个整数x,表示求x位置的值;若该字符为'U',则表示一个撤销操作,接下来一个整数x,表示撤销掉最后进行的若干次操作。

输出

对每一个询问操作单独输出一行,表示答案。

AC代码:

#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> using namespace std; const int N = 1e5 + 5; struct Node { int val; Node *ls, *rs; }pool[N * 20], *tail = pool, *root[N], *zero; int m, x, tot, siz[N]; char opt[10]; Node *newnode () { Node *nd = ++tail; nd -> ls = nd -> rs = zero; nd -> val = 0; return nd; } void init () { zero = ++tail; zero -> ls = zero -> rs = zero; zero -> val = 0; root[0] = newnode (); } Node *modify (Node *rt, int l, int r, int o, int val) { Node *nd = newnode (); if (l == r) { nd -> val = val; } else { int mid = l + r >> 1; if (o <= mid) { nd -> ls = modify (rt -> ls, l, mid, o, val); nd -> rs = rt -> rs; } else { nd -> ls = rt -> ls; nd -> rs = modify (rt -> rs, mid + 1, r, o, val); } } return nd; } int query (Node *nd, int l, int r, int o) { if (l == r) return nd -> val; int mid = l + r >> 1; if (o <= mid) return query (nd -> ls, l, mid, o); else return query (nd -> rs, mid + 1, r, o); } int main () { scanf ("%d", &m); init (); while (m--) { scanf ("%s", opt); scanf ("%d", &x); if (opt[0] == 'A') { tot++; siz[tot] = siz[tot - 1] + 1; root[tot] = modify (root[tot - 1], 1, N, siz[tot], x); } else if (opt[0] == 'Q') { printf ("%d\n", query (root[tot], 1, N, x)); } else { tot++; siz[tot] = siz[tot - x - 1]; root[tot] = root[tot - x - 1]; } } return 0; }

描述

给一个长为N的数列,有M次操作,每次操作是以下两种之一:

(1)将某连续一段同时改成一个数

(2)求数列中某连续一段的和

输入

第一行两个正整数N和M。 第二行N的整数表示这个数列。 接下来M行,每行开头是一个字符,若该字符为'M',则表示一个修改操作,接下来三个整数x、y和z,表示在[x,y]这段区间的数改为z;若该字符为'Q',则表示一个询问操作,接下来两个整数x和y,表示求[x,y]这段区间的和。

输出

对每一个询问操作单独输出一行,表示答案。

AC代码:

#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> using namespace std; typedef long long ll; const int N = 1e5 + 5; struct Node { ll val, tag, flag; Node *ls, *rs; void update (void) { val = ls -> val + rs -> val; } }pool[N << 1], *tail = pool, *root, *zero; ll n, m, a[N]; ll read () { ll x = 0, f = 1; char c = getchar (); while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar ();} while (c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar ();} return x * f; } void init () { zero = ++tail; zero -> ls = zero -> rs = zero; zero -> val = zero -> tag = zero -> flag = 0; } Node *newnode () { Node *nd = ++tail; nd -> ls = nd -> rs = zero; nd -> val = nd -> tag = nd -> flag = 0; return nd; } void push_down (Node *nd, ll l, ll r) { if (nd -> flag) { int mid = l + r >> 1; nd -> ls -> val = nd -> tag * (mid - l + 1); nd -> rs -> val = nd -> tag * (r - mid); nd -> ls -> tag = nd -> rs -> tag = nd -> tag; nd -> ls -> flag = nd -> rs -> flag = 1; nd -> flag = nd -> tag = 0; } } Node *build (ll l, ll r) { Node *nd = newnode (); if (l == r) { nd -> val = a[l]; nd -> tag = nd -> flag = 0; } else { int mid = l + r >> 1; nd -> ls = build (l, mid); nd -> rs = build (mid + 1, r); nd -> update (); } return nd; } void modify (Node *nd, ll l, ll r, ll L, ll R, ll val) { if (L <= l && R >= r) { nd -> val = val * (r - l + 1); nd -> tag = val, nd -> flag = 1; return ; } push_down (nd, l, r); int mid = l + r >> 1; if (L <= mid) modify (nd -> ls, l, mid, L, R, val); if (mid < R) modify (nd -> rs, mid + 1, r, L, R, val); nd -> update (); return ; } ll query (Node *nd, ll l, ll r, ll L, ll R) { if (L <= l && R >= r) return nd -> val; push_down (nd, l, r); int mid = l + r >> 1; ll sww = 0; if (L <= mid) sww += query (nd -> ls, l, mid, L, R); if (mid < R) sww += query (nd -> rs, mid + 1, r, L, R); return sww; } int main () { n = read (), m = read (); for (int i = 1; i <= n; i++) a[i] = read (); init (), root = build (1, n); while (m--) { char opt = getchar (); while (opt != 'M' && opt != 'Q') opt = getchar (); if (opt == 'M') { int x, y, z; x = read (), y = read (), z = read (); modify (root, 1, n, x, y, z); } else { int x, y; x = read (), y = read (); printf ("%lld\n", query (root, 1, n, x, y)); } } return 0; }

描述

给一个长为N的数列,有M次操作,每次操作是以下两种之一:

(1)修改数列中的一个数

(2)求数列中有多少个数比它前面的数都大

输入

第一行两个正整数N和M。 第二行N的整数表示这个数列。 接下来M行,每行开头是一个字符,若该字符为'M',则表示一个修改操作,接下来两个整数x和y,表示把x位置的值修改为y;若该字符为'Q',则表示一个询问操作,求数列中有多少个数比它前面的数都大。

输出

对每一个询问操作单独输出一行,表示答案。

这道题和楼房重建(bzoj2957)是一样的

AC代码:

#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> using namespace std; const int N = 1e5 + 3; struct Node { int val, sww; Node *ls, *rs; }pool[N << 1], *tail = pool, *root; int n, m, a[N]; int read () { int x = 0, f = 1; char c = getchar (); while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar ();} while (c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar ();} return x * f; } int query (Node *nd, int l, int r, int val) { if (l == r) return nd -> val > val; int mid = l + r >> 1; if (nd -> ls -> val <= val) return query (nd -> rs, mid + 1, r, val); else return nd -> sww - nd -> ls -> sww + query (nd -> ls, l, mid, val); } void update (Node *nd, int l, int r) { nd -> val = max (nd -> ls -> val, nd -> rs -> val); int mid = l + r >> 1; nd -> sww = nd -> ls -> sww + query (nd -> rs, mid + 1, r, nd -> ls -> val); } Node *build (int l, int r) { Node *nd = ++tail; if (l == r) { nd -> val = a[l]; nd -> sww = 1; } else { int mid = l + r >> 1; nd -> ls = build (l, mid); nd -> rs = build (mid + 1, r); update (nd, l, r); } return nd; } void modify (Node *nd, int l, int r, int o, int val) { if (l == r) { nd -> val = val; nd -> sww = 1; return ; } int mid = l + r >> 1; if (o <= mid) modify (nd -> ls, l, mid, o, val); else modify (nd -> rs, mid + 1, r, o, val); update (nd, l, r); return ; } int main () { n = read (), m = read (); for (int i = 1; i <= n; i++) a[i] = read (); root = build (1, n); while (m--) { char opt = getchar (); while (opt != 'M' && opt != 'Q') opt = getchar (); if (opt == 'M') { int x = read (), y = read (); modify (root, 1, n, x, y); } else { printf ("%d\n", root -> sww); } } return 0; }

 

转载请注明原文地址: https://www.6miu.com/read-5037492.html

最新回复(0)