这一部分的功能和树状数组一样,这里是树状数组的模板
除了求和之外,还能解决区间最小最大值,区间染色
1 单点修改,区间查询
#include <bits/stdc++.h> using namespace std; #define int long long const int maxn = 5e5 + 10; struct node{ int l,r; int sum; }tree[maxn * 4]; int n,m,a[maxn]; void build(int i,int l,int r){ tree[i].l = l; tree[i].r = r; if(l==r){ tree[i].sum = a[l]; return; } int mid = (l + r)/ 2; build(i * 2,l,mid); build(i * 2 + 1,mid + 1,r); tree[i].sum = tree[i * 2].sum + tree[i * 2 + 1].sum; } //区间查询 int search(int i,int l,int r){ //这个区间被完全包括在目标区间里面,返回这个区间的值 if(tree[i].l >= l && tree[i].r <= r) return tree[i].sum; //这个区间和目标区间不相干 if(tree[i].l > r || tree[i].r < l) return 0; int s = 0; //这个区间的左儿子和目标区间有交集 if(tree[i * 2].r >= l) s += search(i * 2,l,r); //这个区间的右儿子和目标区间有交集 if(tree[i * 2 + 1].l <= r) s += search(i * 2 + 1,l,r); return s; } //单点修改 void add(int i ,int dis,int k){ //如果是叶子节点,则说明找到了 if(tree[i].l == tree[i].r){ tree[i].sum += k; return; } if(dis <= tree[i * 2].r) add(i * 2,dis,k); else add(i * 2 + 1,dis,k); tree[i].sum = tree[i * 2].sum + tree[i * 2 + 1].sum; return; } signed main(){ //freopen("in","r",stdin); ios::sync_with_stdio(0); cin >> n >> m; for(int i = 1; i <= n; i++) cin >> a[i]; build(1,1,n); while(m--){ int op,x,y; cin >> op >> x >> y; if(op == 1) add(1,x,y); else cout << search(1,x,y) << endl; } return 0; }
2 区间修改,单点查询
#include <bits/stdc++.h> using namespace std; #define int long long const int maxn = 5e5 + 10; struct node{ int l,r; int sum; }tree[maxn * 4]; int n,m,a[maxn]; int ans; void build(int i,int l,int r){ tree[i].sum = 0; tree[i].l = l; tree[i].r = r; if(l==r) return; int mid = (l + r)/ 2; build(i * 2,l,mid); build(i * 2 + 1,mid + 1,r); tree[i].sum = tree[i * 2].sum + tree[i * 2 + 1].sum; } void search(int i,int dis){ ans += tree[i].sum; if(tree[i].l == tree[i].r) return; if(dis <= tree[i * 2].r) search(i * 2,dis); if(dis >= tree[i * 2 + 1].l) search(i * 2 + 1,dis); } void add(int i ,int l,int r,int k){ if(tree[i].l >= l && tree[i].r <= r){ tree[i].sum += k; return; } if(tree[i * 2].r >= l) add(i * 2,l,r,k); if(tree[i * 2 + 1].l <= r) add(i * 2 + 1,l,r,k); } signed main(){ //freopen("in","r",stdin); ios::sync_with_stdio(0); cin >> n >> m; for(int i = 1; i <= n; i++) cin >> a[i]; build(1,1,n); while(m--){ int op,x,y,k; cin >> op; if(op == 1) { cin >> x >> y >> k; add(1,x,y,k); } else { cin >> x; ans = 0; search(1,x); cout << ans + a[x] << endl; } } return 0; }
进阶线段树(区间加减)
区间修改 区间查询
区间修改
//把自己的lazytage归零,并且给自己的儿子加上
void pushdown(int i){ if(tree[i].lz){ tree[i * 2].lz += tree[i].lz;//左右儿子分别加上父亲的lz tree[i * 2 + 1].lz += tree[i].lz; int mid = (tree[i].l + tree[i].r)/ 2; //左右分别加起来 tree[i * 2].sum += tree[i].lz *(mid - tree[i * 2].l + 1); tree[i * 2 + 1].sum += tree[i].lz * (tree[i * 2 + 1].r - mid); tree[i].lz = 0;//父亲lz归0 } return; }
//区间修改(数据更新)
void add(int i ,int l,int r,int k){ //如果这个区间完全包括在目标区间内 if(tree[i].l >= l && tree[i].r <= r){ tree[i].sum += k*(tree[i].r - tree[i].l + 1); tree[i].lz += k;//记录lazytage return; } pushdown(i);//向下传递 if(tree[i * 2].r >= l) add(i * 2,l,r,k); if(tree[i * 2 + 1].l <= r) add(i * 2 + 1,l,r,k); tree[i].sum = tree[i * 2].sum + tree[i * 2 + 1].sum; return; }
区间查询
int search(int i,int l,int r){ if(tree[i].l >= l && tree[i].r <= r) return tree[i].sum; if(tree[i].r < l || tree[i].l > r) return 0; pushdown(i); int s = 0; if(tree[i * 2].r >= l) s += search(i * 2,l,r); if(tree[i * 2 + 1].l <= r) s += search(i * 2 + 1,l,r); return s; }
#include <bits/stdc++.h> using namespace std; #define int long long const int maxn = 5e5 + 10; struct node{ int l,r; int sum; int lz;//lazytage }tree[maxn * 4]; int n,m,a[maxn]; void build(int i,int l,int r){ tree[i].lz = 0; tree[i].l = l; tree[i].r = r; if(l==r){ tree[i].sum = a[l]; return; } int mid = (l + r)/ 2; build(i * 2,l,mid); build(i * 2 + 1,mid + 1,r); tree[i].sum = tree[i * 2].sum + tree[i * 2 + 1].sum; } //把自己的lazytage归零,并且给自己的儿子加上 void pushdown(int i){ if(tree[i].lz){ tree[i * 2].lz += tree[i].lz;//左右儿子分别加上父亲的lz tree[i * 2 + 1].lz += tree[i].lz; int mid = (tree[i].l + tree[i].r)/ 2; //左右分别加起来 tree[i * 2].sum += tree[i].lz *(mid - tree[i * 2].l + 1); tree[i * 2 + 1].sum += tree[i].lz * (tree[i * 2 + 1].r - mid); tree[i].lz = 0;//父亲lz归0 } return; } //区间修改(数据更新) void add(int i ,int l,int r,int k){ //如果这个区间完全包括在目标区间内 if(tree[i].l >= l && tree[i].r <= r){ tree[i].sum += k*(tree[i].r - tree[i].l + 1); tree[i].lz += k;//记录lazytage return; } pushdown(i);//向下传递 if(tree[i * 2].r >= l) add(i * 2,l,r,k); if(tree[i * 2 + 1].l <= r) add(i * 2 + 1,l,r,k); tree[i].sum = tree[i * 2].sum + tree[i * 2 + 1].sum; return; } int search(int i,int l,int r){ if(tree[i].l >= l && tree[i].r <= r) return tree[i].sum; if(tree[i].r < l || tree[i].l > r) return 0; pushdown(i); int s = 0; if(tree[i * 2].r >= l) s += search(i * 2,l,r); if(tree[i * 2 + 1].l <= r) s += search(i * 2 + 1,l,r); return s; } signed main(){ //freopen("in","r",stdin); ios::sync_with_stdio(0); cin >> n >> m; for(int i = 1; i <= n; i++) cin >> a[i]; build(1,1,n); while(m--){ int op,x,y,k; cin >> op; if(op == 1) { cin >> x >> y >> k; add(1,x,y,k); } else { cin >> x >> y; cout << search(1,x,y) << endl; } } return 0; }
乘法/sqrt线段树
#include <bits/stdc++.h> using namespace std; #define int long long const int maxn = 5e5 + 10; struct node{ int l,r; int sum; int plz,mlz;//lazytage分为两种,加法plz 乘法 mlz }tree[maxn * 4]; int n,m,p,a[maxn]; void build(int i,int l,int r){ tree[i].mlz = 1; tree[i].l = l; tree[i].r = r; if(l==r){ tree[i].sum = a[l] % p; return; } int mid = (l + r)/ 2; build(i * 2,l,mid); build(i * 2 + 1,mid + 1,r); tree[i].sum = (tree[i * 2].sum + tree[i * 2 + 1].sum) % p; return; } void pushdown(int i){ int k1=tree[i].mlz,k2=tree[i].plz; tree[i * 2].sum=(tree[i * 2].sum*k1 + k2* (tree[i * 2].r - tree[i * 2].l+1))%p; tree[i * 2 + 1].sum=(tree[i * 2 + 1].sum * k1+k2*(tree[i * 2 + 1].r-tree[i * 2 + 1].l + 1))%p; tree[i * 2].mlz=(tree[i * 2].mlz*k1)%p; tree[i * 2 + 1].mlz=(tree[i * 2 + 1].mlz*k1)%p; tree[i * 2].plz=( tree[i * 2].plz *k1 + k2)%p; tree[i * 2 + 1].plz=(tree[i * 2 + 1].plz * k1 + k2)%p; tree[i].plz=0; tree[i].mlz=1; return ; } void mul(int i ,int l,int r,int k){ if(tree[i].r < l || tree[i].l > r) return ; //如果这个区间完全包括在目标区间内 if(tree[i].l >= l && tree[i].r <= r){ tree[i].sum = ( k * tree[i].sum) % p; tree[i].mlz = (tree[i].mlz * k) % p; tree[i].plz = (tree[i].plz * k) % p; return; } pushdown(i);//向下传递 if(tree[i * 2].r >= l) mul(i * 2,l,r,k); if(tree[i * 2 + 1].l <= r) mul(i * 2 + 1,l,r,k); tree[i].sum = (tree[i * 2].sum + tree[i * 2 + 1].sum) % p; return; } void add(int i ,int l,int r,int k){ if(tree[i].r < l || tree[i].l > r) return ; //如果这个区间完全包括在目标区间内 if(tree[i].l >= l && tree[i].r <= r){ tree[i].sum += (k *(tree[i].r - tree[i].l + 1)) % p; tree[i].plz = (tree[i].plz + k) % p; return; } pushdown(i);//向下传递 if(tree[i * 2].r >= l) add(i * 2,l,r,k); if(tree[i * 2 + 1].l <= r) add(i * 2 + 1,l,r,k); tree[i].sum = (tree[i * 2].sum + tree[i * 2 + 1].sum) % p; return; } int search(int i,int l,int r){ if(tree[i].r < l || tree[i].l > r) return 0; if(tree[i].l >= l && tree[i].r <= r) return tree[i].sum; pushdown(i); int s = 0; if(tree[i * 2].r >= l) s += search(i * 2,l,r) % p; if(tree[i * 2 + 1].l <= r) s += search(i * 2 + 1,l,r) % p; return s % p; } signed main(){ // freopen("in","r",stdin); ios::sync_with_stdio(0); cin >> n >> m >> p; for(int i = 1; i <= n; i++) cin >> a[i]; build(1,1,n); while(m--){ int op,x,y,k; cin >> op; if(op == 1) { cin >> x >> y >> k; k %= p; mul(1,x,y,k); } else if(op == 2){ cin >> x >> y >> k; k %= p; add(1,x,y,k); }else{ cin >> x >> y; cout << search(1,x,y) << endl; } } return 0; }