线段树基本操作

query()

int query(int u, int l, int r) {
    //查询操作
	if (tr[u].l >= l && tr[u].r <= r)return tr[u].v; //树中节点已经被完全包含在[l,r]中

	int mid = tr[u].l + tr[u].r >> 1;
	int v = 0;
	if(l > mid)return query(u << 1 | 1,l,r);
    else if(r <= mid)return query(u << 1,l,r);
    else{
   
        int a = query(u << 1,l,r);
        int b = query(u << 1 | 1, l, r);
        return max(a,b);
    }

	return v;
}

build()

void build(int u, int l, int r) {
    //建树
	tr[u].l = l, tr[u].r = r; 
	if (l == r)return;
	int mid = l + r >> 1;
	build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
}

modify()

void modify(int u, int x, int v) {
    //u表示当前线段树区间 x表示待修改的位置 v表示修改的值
	if (tr[u].l == x && tr[u].r == x)tr[u].v = v;
	else {
   
		int mid = tr[u].l + tr[u].r >> 1;
		if (x <= mid)modify(u << 1, x, v);
		else modify(u << 1 | 1, x, v);
		pushup(u);
	}
}

pushup()

void pushup(Node& u, Node& l, Node& r) {
   
	u.sum = l.sum + r.sum;
	u.d = gcd(l.d, r.d);
}
void pushup(int u) {
   
	pushup(tr[u], tr[u << 1], tr[u << 1 | 1]);
}

pushdown()

void pushdown(int u) {
   
	node& root = tr[u];
	node& left = tr[u << 1];
	node& right = tr[u << 1 | 1];
	if (root.add) {
   
		left.sum += (LL)(left.r - left.l + 1) * root.add;
		right.sum += (LL)(right.r - right.l + 1) * root.add;
		left.add += root.add;
		right.add += root.add;
		root.add = 0;
	}
}

AcWing. 1275最大数

给定一个正整数数列 a1,a2,…,an,每一个数都在 0∼p−1 之间。

可以对这列数进行两种操作:

  1. 添加操作:向序列后添加一个数,序列长度变成 n+1;
  2. 询问操作:询问这个序列中最后 L 个数中最大的数是多少。

程序运行的最开始,整数序列为空。

写一个程序,读入操作的序列,并输出询问操作的答案。

输入格式

第一行有两个正整数 m,p,意义如题目描述;

接下来 m 行,每一行表示一个操作。

如果该行的内容是 Q L,则表示这个操作是询问序列中最后 L 个数的最大数是多少;

如果是 A t,则表示向序列后面加一个数,加入的数是 (t+a) mod p。其中,t 是输入的参数,a 是在这个添加操作之前最后一个询问操作的答案(如果之前没有询问操作,则 a=0)。

第一个操作一定是添加操作。对于询问操作,L>0 且不超过当前序列的长度。

输出格式

对于每一个询问操作,输出一行。该行只有一个数,即序列中最后 L 个数的最大数。

数据范围

1 ≤ m ≤ 2 × 1 0 5 1≤m≤2×10^{5} 1m2×105
1 ≤ p ≤ 2 × 1 0 9 1≤p≤2×10^{9} 1p2×109
0 ≤ t < p 0≤t<p 0t<p

代码

#include<iostream>
#include<cstdio>
#include<queue>
#include<string>
#include<cstring>
#include<map>
#include<vector>
#include<set>
#include<stack>
#include<algorithm>
#include<vector>
#include<utility>
#include<deque>
#include<unordered_map>
#define INF 0x3f3f3f3f
#define mod 1000000007
#define endl '\n'
#define eps 1e-6
inline int gcd(int a, int b) {
    return b ? gcd(b, a % b) : a; }
inline int lowbit(int x) {
    return x & -x; }


using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
const int N = 200010;

int m, p;
struct Node {
   
	int l, r;
	int v;
}tr[N * 4];

void pushup(int u) {
    // 由子节点的信息计算父节点的信息
	tr[u].v = max(tr[u << 1].v, tr[u << 1 | 1].v);
}

void build(int u, int l, int r) {
    //建树
	tr[u].l = l, tr[u].r = r; 
	if (l == r)return;
	int mid = l + r >> 1;
	build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
}

int query(int u, int l, int r) {
    //查询操作
	if (tr[u].l >= l && tr[u].r <= r)return tr[u].v; //树中节点已经被完全包含在[l,r]中

	int mid = tr[u].l + tr[u].r >> 1;
	int v = 0;
	if(l > mid)return query(u << 1 | 1,l,r);
    else if(r <= mid)return query(u << 1,l,r);
    else{
   
        int a = query(u << 1,l,r);
        int b = query(u << 1 | 1, l, r);
        return max(a,b);
    }

	return v;
}

void modify(int u, int x, int v) {
    //u表示当前线段树区间 x表示待修改的位置 v表示修改的值
	if (tr[u].l == x && tr[u].r == x)tr[u].v = v;
	else {
   
		int mid = tr[u].l + tr[u].r >> 1;
		if (x <= mid)modify(u << 1, x, v);
		else modify(u << 1 | 1, x, v);
		pushup(u);
	}
}

int main() {
   
	int n = 0;
	int last = 0;

	scanf("%d%d", &m, &p);

	build(1, 1, m);
	char op[2];
	int x = 0;
	while (m--) {
   
		scanf("%s%d", op, &x);

		if (op[0] == 'Q') {
   
			last = query(1, n - x + 1, n); //查询最后x个数
			printf("%d\n", last);
		}
		else {
   
			modify(1, n + 1, (last + x) % p);//修改第n+1个数 相当于在最后插入一个数
			++n;
		}
	}

	return 0;
}

AcWing. 245你能回答这些问题吗(最大连续区间子段和)

给定长度为N的数列A,以及M条指令,每条指令可能是以下两种之一:

1、“1 x y”,查询区间 [x,y] 中的最大连续子段和,即 m a x x ≤ l ≤ r ≤ y max_{x \leq l \leq r \leq y} maxxlry ∑ i = l r A [ i ] {\sum^{r}_{i = l}A[i]} i=lrA[i]

2、“2 x y”,把 A[x] 改成 y。

对于每个查询指令,输出一个整数表示答案。

输入格式

第一行两个整数N,M。

第二行N个整数A[i]。

接下来M行每行3个整数k,x,y,k=1表示查询(此时如果x>y,请交换x,y),k=2表示修改。

输出格式

对于每个查询指令输出一个整数表示答案。

每个答案占一行。

数据范围

N ≤ 500000 , M ≤ 100000 N≤500000,M≤100000 N500000,M100000

代码

#include<iostream>
#include<cstdio>
#include<queue>
#include<string>
#include<cstring>
#include<map>
#include<vector>
#include<set>
#include<stack>
#include<algorithm>
#include<vector>
#include<utility>
#include<deque>
#include<unordered_map>
#define INF 0x3f3f3f3f
#define mod 1000000007
#define endl '\n'
#define eps 1e-6
inline int gcd(int a, int b) {
    return b ? gcd(b, a % b) : a; }
inline int lowbit(int x) {
    return x & -x; }


using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
const int N = 500010;

int n, m;
int a[N];
struct Node {
   
	int l, r; //区间左右端点
	int tmax; //最大连续子段和
	int lmax; //最大前缀
	int rmax; //最大后缀
	int sum;  //区间和
}tr[N * 4];
void pushup(Node& u, Node& l, Node& r) {
   
	u.sum = l.sum + r.sum;
	u.lmax = max(l.lmax, l.sum + r.lmax);
	u.rmax = max(r.rmax, r.sum + l.rmax);

	u.tmax = max(l.tmax, r.tmax);
	u.tmax = max(u.tmax, l.rmax + r.lmax);
}

void pushup(int u) {
   
	pushup(tr[u], tr[u << 1], tr[u << 1 | 1]);
}

void build(int u, int l, int r) {
   
	if (l == r)tr[u] = {
    l,r,a[r],a[r],a[r],a[r] };
	else {
   
		tr[u] = {
    l,r };
		int mid = l + r >> 1;
		build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
		pushup(u);
	}
}

int modify(int u, int x, int v) {
   
	if (tr[u].l == x && tr[u].r == x)tr[u] = {
    x,x,v,v,v,v };
	else {
   
		int mid = tr[u].l + tr[u].r >> 1;
		if (x <= mid)modify(u << 1, x, v);
		else modify(u << 1 | 1, x, v);
		pushup(u);
	}
}

Node query(int u,int l,int r) {
   
	if (tr[u].l >= l && tr[u].r <= r)return tr[u];
	else {
   
		int mid = tr[u].l + tr[u].r >> 1;
		if (r <= mid)return query(u << 1, l, r);
		else if (l > mid)return query(u << 1 | 1, l, r);
		else {
   
			auto left = query(u << 1, l, r);
			auto right = query(u << 1 | 1, l, r);
			Node res;
			pushup(res, left, right);
			return res;
		}
	}
}
int main() {
   
	scanf("%d%d", &n, &m);

	for (int i = 1; i <= n;++i)scanf("%d", &a[i]);

	build(1, 1, n);

	int k, x, y;
	while (m--) {
   
		scanf("%d%d%d", &k, &x, &y);
		if (k == 1) {
   
			if (x > y)swap(x, y);
			printf("%d\n", query(1, x, y).tmax);
		}
		else modify(1, x, y);
	}
}

AcWing. 246区间最大公约数

g c d ( a 1 , a 2 . . . , a n ) gcd(a_{1},a_{2}...,a_{n}) gcd(a1,a2...,an) = g c d ( a 1 , a 2 − a 1 . . . , a n − a n − 1 ) gcd(a_{1},a_{2}-a_{1}...,a_{n}-a{n-1}) gcd(a1,a2a1...,anan1)

给定一个长度为N的数列A,以及M条指令,每条指令可能是以下两种之一:

1、“C l r d”,表示把 A[l],A[l+1],…,A[r] 都加上 d。

2、“Q l r”,表示询问 A[l],A[l+1],…,A[r] 的最大公约数(GCD)。

对于每个询问,输出一个整数表示答案。

输入格式

第一行两个整数N,M。

第二行N个整数A[i]。

接下来M行表示M条指令,每条指令的格式如题目描述所示。

输出格式

对于每个询问,输出一个整数表示答案。

每个答案占一行。

数据范围

N ≤ 500000 , M ≤ 100000 N≤500000,M≤100000 N500000,M100000

代码

#include<iostream>
#include<cstdio>
#include<queue>
#include<string>
#include<cstring>
#include<map>
#include<vector>
#include<set>
#include<stack>
#include<cmath>
#include<algorithm>
#include<vector>
#include<utility>
#include<deque>
#define INF 0x3f3f3f3f
#define mod 1000000007
#define fi first
#define se second
#define pb push_back
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define endl '\n'
#define eps 1e-6
#define mem(n,a) memset(n,a,sizeof(n))
#define rep(i,be,en) for(int i=be;i<=en;++i)
#define pre(i,be,en) for(int i=en;i>=be;--i)
inline int gcd(int a, int b) {
    return b ? gcd(b, a % b) : a; }
inline int lowbit(int x) {
    return x & -x; }


using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;

const int N = 500010;
struct Node {
   
	int l, r;
	LL sum, d;
}tr[N * 4];
int n, m;
LL w[N];
LL gcd(LL a, LL b) {
   
	return b ? gcd(b, a % b) : a;
}
void pushup(Node& u, Node& l, Node& r) {
   
	u.sum = l.sum + r.sum;
	u.d = gcd(l.d, r.d);
}
void pushup(int u) {
   
	pushup(tr[u], tr[u << 1], tr[u << 1 | 1]);
}
void build(int u, int l,int r) {
   
	if (l == r) {
   
		LL b = w[r] - w[r - 1];
		tr[u] = {
    r,r,b,b };
	}
	else {
   
		tr[u].l = l, tr[u].r = r;
		int mid = l + r >> 1;
		build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
		pushup(u);
	}
}

void modify(int u, int x, LL v) {
   
	if (tr[u].l == x && tr[u].r == x) {
   
		LL b = tr[u].sum + v;
		tr[u] = {
    x,x,b,b };
	}
	else {
   
		int mid = tr[u].l + tr[u].r >> 1;
		if (x <= mid)modify(u << 1, x, v);
		else modify(u << 1 | 1, x, v);
		pushup(u);
	}
}

Node query(int u, int l, int r) {
   
	if (tr[u].l >= l && tr[u].r <= r)return tr[u];
	else {
   
		int mid = tr[u].l + tr[u].r >> 1;
		if (r <= mid)return query(u << 1, l, r);
		else if (l > mid)return query(u << 1 | 1, l, r);
		else{
   
			auto left = query(u << 1, l, r);
			auto right = query(u << 1 | 1, l, r);
			Node res;
			pushup(res, left, right);
			return res;
		}
	}
}

int main() {
   
	scanf("%d%d", &n, &m);

	for (int i = 1; i <= n;++i)scanf("%lld", &w[i]);
	build(1, 1, n);

	char op[2];
	int l, r;
	LL d;

	while (m--) {
   
		scanf("%s%d%d", op, &l, &r);
		if (op[0] == 'Q') {
   
			auto left = query(1, 1, l);
			Node right = {
    0,0,0,0 };
			if (l + 1 <= r)right = query(1,l + 1, r);
			printf("%lld\n", abs(gcd(left.sum, right.d)));
		}
		else {
   
			scanf("%lld", &d);
			modify(1, l, d);
			if (r + 1 <= n)modify(1, r + 1, -d);
		}
	}
}

AcWing243. 一个简单的整数问题2(区间修改)

给定一个长度为N的数列A,以及M条指令,每条指令可能是以下两种之一:

1、“C l r d”,表示把 A[l],A[l+1],…,A[r] 都加上 d。

2、“Q l r”,表示询问 数列中第 l~r 个数的和。

对于每个询问,输出一个整数表示答案。

输入格式

第一行两个整数N,M。

第二行N个整数A[i]。

接下来M行表示M条指令,每条指令的格式如题目描述所示。

输出格式

对于每个询问,输出一个整数表示答案。

每个答案占一行。

数据范围

1 ≤ N , M ≤ 1 0 5 , 1≤N,M≤10^{5}, 1N,M105,
∣ d ∣ ≤ 10000 |d|≤10000 d10000
∣ A [ i ] ∣ ≤ 1000000000 |A[i]|≤1000000000 A[i]1000000000

代码

#include<iostream>
#include<cstdio>
#include<queue>
#include<string>
#include<cstring>
#include<map>
#include<vector>
#include<set>
#include<stack>
#include<cmath>
#include<algorithm>
#include<vector>
#include<utility>
#include<deque>
#define INF 0x3f3f3f3f
#define INFL 0x3f3f3f3f3f3f3f3f
#define mod 1000000007
#define fi first
#define se second
#define pb push_back
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define endl '\n'
#define eps 1e-6
#define mem(n,a) memset(n,a,sizeof(n))
#define rep(i,be,en) for(int i=be;i<=en;++i)
#define pre(i,be,en) for(int i=en;i>=be;--i)
inline int gcd(int a, int b) {
    return b ? gcd(b, a % b) : a; }
inline int lowbit(int x) {
    return x & -x; }


using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
const int N = 100100;

int a[N];
struct node {
   
	int l, r;
	LL sum, add;
}tr[N << 2];

void pushup(int u) {
   
	tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}

void pushdown(int u) {
   
	node& root = tr[u];
	node& left = tr[u << 1];
	node& right = tr[u << 1 | 1];
	if (root.add) {
   
		left.sum += (LL)(left.r - left.l + 1) * root.add;
		right.sum += (LL)(right.r - right.l + 1) * root.add;
		left.add += root.add;
		right.add += root.add;
		root.add = 0;
	}
}

void build(int u, int l, int r) {
   
	if (l == r) {
   
		tr[u] = {
    r,r,(LL)a[r],0 };
	}
	else {
   
		tr[u].l = l, tr[u].r = r;
		int mid = l + r >> 1;
		build(u << 1, l, mid);build(u << 1 | 1, mid + 1, r);
		pushup(u);
	}
}

void modify(int u, int l, int r, int d) {
   
	if (tr[u].l >= l && tr[u].r <= r) {
   
		tr[u].sum += (LL)(tr[u].r - tr[u].l + 1) * d;
		tr[u].add += d;
	}
	else {
   
		pushdown(u);
		int mid = tr[u].l + tr[u].r >> 1;
		if (l <= mid)modify(u << 1, l, r, d);
		if (r > mid)modify(u << 1 | 1, l, r, d);
		pushup(u);
	}
}

LL query(int u, int l, int r) {
   
	if (tr[u].l >= l && tr[u].r <= r)return tr[u].sum;

	pushdown(u);
	int mid = tr[u].l + tr[u].r >> 1;
	LL sum = 0;
	if (l <= mid)sum = query(u << 1, l, r);
	if (r > mid)sum += query(u << 1 | 1, l, r);
	return sum;
}

int main() {
   
	int n, m;scanf("%d%d", &n, &m);
	for (int i = 1; i <= n;++i)scanf("%d", &a[i]);
	build(1, 1, n);

	char op[2];
	int l, r, d;
	while (m--) {
   
		
		scanf("%s%d%d", op, &l, &r);
		if (op[0] == 'Q') {
   
			printf("%lld\n", query(1, l, r));
		}
		else {
   
			scanf("%d", &d);
			modify(1, l, r, d);
		}
	}

	return 0;
}

AcWing1277. 维护序列(区间修改)

老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。

有长为 NN 的数列,不妨设为 a1,a2,…,aNa1,a2,…,aN。

有如下三种操作形式:

  1. 把数列中的一段数全部乘一个值;
  2. 把数列中的一段数全部加一个值;
  3. 询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模 PP 的值。

输入格式

第一行两个整数 NN 和 PP;

第二行含有 NN 个非负整数,从左到右依次为 a1,a2,…,aNa1,a2,…,aN;

第三行有一个整数 MM,表示操作总数;

从第四行开始每行描述一个操作,输入的操作有以下三种形式:

  • 操作 11:1 t g c,表示把所有满足 t≤i≤gt≤i≤g 的 aiai 改为 ai×cai×c;
  • 操作 22:2 t g c,表示把所有满足 t≤i≤gt≤i≤g 的 aiai 改为 ai+cai+c;
  • 操作 33:3 t g,询问所有满足 t≤i≤gt≤i≤g 的 aiai 的和模 PP 的值。

同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。

输出格式

对每个操作 33,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。

数据范围

1 ≤ N , M ≤ 1 0 5 1≤N,M≤10^{5} 1N,M105
1 ≤ t ≤ g ≤ N 1≤t≤g≤N 1tgN,
0 ≤ c , a i ≤ 1 0 9 0≤c,ai≤10^{9} 0c,ai109,
1 ≤ P ≤ 1 0 9 1≤P≤10^{9} 1P109

代码

#include<iostream>
#include<cstdio>
#include<queue>
#include<string>
#include<cstring>
#include<map>
#include<vector>
#include<set>
#include<stack>
#include<cmath>
#include<algorithm>
#include<vector>
#include<utility>
#include<deque>
#define INF 0x3f3f3f3f
#define INFL 0x3f3f3f3f3f3f3f3f
#define mod 1000000007
#define fi first
#define se second
#define pb push_back
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define endl '\n'
#define eps 1e-6
#define mem(n,a) memset(n,a,sizeof(n))
#define rep(i,be,en) for(int i=be;i<=en;++i)
#define pre(i,be,en) for(int i=en;i>=be;--i)
inline int gcd(int a, int b) {
    return b ? gcd(b, a % b) : a; }
inline int lowbit(int x) {
    return x & -x; }


using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
const int N = 100100;

int n,m, p;
int w[N];

struct node {
   
	int l, r;
	LL sum, add, mul;
}tr[4 * N];

void pushup(int u) {
   
	tr[u].sum = LL(tr[u << 1].sum + tr[u << 1 | 1].sum) % p;
}

void eval(node& t, int add, int mul) {
   
	t.sum = ((LL)t.sum * mul + (LL)(t.r - t.l + 1) * add) % p;
	t.mul = (LL)t.mul * mul % p;
	t.add = ((LL)t.add * mul + add) % p;
}

void pushdown(int u) {
   
	eval(tr[u << 1], tr[u].add, tr[u].mul);
	eval(tr[u << 1 | 1], tr[u].add, tr[u].mul);
	tr[u].add = 0;
	tr[u].mul = 1;
}

void build(int u, int l, int r) {
   
	if (l == r) {
   
		tr[u] = {
    r,r,w[r],0,1 };
	}
	else {
   
		tr[u] = {
    l,r,0,0,1 };
		int mid = l + r >> 1;
		build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
		pushup(u);
	}
}

void modify(int u, int l, int r, int add, int mul) {
   
	if (tr[u].l >= l && tr[u].r <= r)eval(tr[u], add, mul);
	else {
   
		pushdown(u);
		int mid = tr[u].l + tr[u].r >> 1;
		if (l <= mid)modify(u << 1, l, r, add, mul);
		if (r > mid)modify(u << 1 | 1, l, r, add, mul);
		pushup(u);
	}
}

int query(int u, int l, int r) {
   
	if (tr[u].l >= l && tr[u].r <= r)return tr[u].sum % p;
	else {
   
		pushdown(u);
		int mid = tr[u].l + tr[u].r >> 1;
		LL sum = 0;
		if (l <= mid)sum = query(u << 1, l, r);
		if (r > mid)sum = (sum + query(u << 1 | 1, l, r)) % p;
		return sum;
	}
}
int main() {
   
	cin >> n >> p;
	for (int i = 1;i <= n;++i)scanf("%d", &w[i]);

	build(1, 1, n);
	cin >> m;
	int t, l, r, d;
	while (m--) {
   
		scanf("%d%d%d", &t, &l, &r);
		if (t == 1) {
   
			scanf("%d", &d);
			modify(1, l, r, 0, d);
		}
		else if (t == 2) {
   
			scanf("%d", &d);
			modify(1, l, r, d, 1);
		}
		else {
   
			printf("%d\n", query(1, l, r));
		}
	}

	return 0;
}