線段樹相關練習
任重而道遠
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;
}