线段树相关练习

任重而道远

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

猜你喜欢

转载自blog.csdn.net/INTEGRATOR_37/article/details/83385288