线段树基本操作
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 之间。
可以对这列数进行两种操作:
- 添加操作:向序列后添加一个数,序列长度变成 n+1;
- 询问操作:询问这个序列中最后 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} 1≤m≤2×105
1 ≤ p ≤ 2 × 1 0 9 1≤p≤2×10^{9} 1≤p≤2×109
0 ≤ t < p 0≤t<p 0≤t<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} maxx≤l≤r≤y ∑ 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 N≤500000,M≤100000
代码
#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,a2−a1...,an−an−1)
给定一个长度为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 N≤500000,M≤100000
代码
#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}, 1≤N,M≤105,
∣ d ∣ ≤ 10000 |d|≤10000 ∣d∣≤10000
∣ 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。
有如下三种操作形式:
- 把数列中的一段数全部乘一个值;
- 把数列中的一段数全部加一个值;
- 询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模 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} 1≤N,M≤105
1 ≤ t ≤ g ≤ N 1≤t≤g≤N 1≤t≤g≤N,
0 ≤ c , a i ≤ 1 0 9 0≤c,ai≤10^{9} 0≤c,ai≤109,
1 ≤ P ≤ 1 0 9 1≤P≤10^{9} 1≤P≤109
代码
#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;
}