线段树(模板)

【模板】线段树 1https://www.luogu.com.cn/problem/P3372【模板】线段树 2https://www.luogu.com.cn/problem/P3373

【模板】树状数组 1https://www.luogu.com.cn/problem/P3374【模板】树状数组 2https://www.luogu.com.cn/problem/P3368【模板】可持久化线段树 2icon-default.png?t=N3I4https://www.luogu.com.cn/problem/P3834

模板1

单点修改+区间查询

线段树

#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+3;
int f[maxn*4],a[maxn];
int n,m;
void buildtree(int k,int l,int r){
	if(l==r){
		f[k]=a[l];
		return;
	}
	int m=(l+r)>>1;
	buildtree(k+k,l,m);
	buildtree(k+k+1,m+1,r);
	f[k]=f[k+k]+f[k+k+1];
}
void add(int k,int l,int r,int x,int y){
	f[k]+=y;
	if(l==r)
		return;
	int m=(l+r)>>1;
	if(x<=m)
		add(k+k,l,m,x,y);
	else
		add(k+k+1,m+1,r,x,y);
}
int cale(int k,int l,int r,int s,int t){
	if(l==s&&r==t){
		return f[k];
	}
	int m=(l+r)>>1;
	if(t<=m)
		return cale(k+k,l,m,s,t);
	else
		if(s>m)
			return cale(k+k+1,m+1,r,s,t);
		else
			return cale(k+k,l,m,s,m)+cale(k+k+1,m+1,r,m+1,t);
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>a[i];
	buildtree(1,1,n);	
	for(int i=1;i<=m;i++){
		int t,x,y;
		cin>>t>>x>>y;
		if(t==1)
			add(1,1,n,x,y);
		else
			printf("%d\n",cale(1,1,n,x,y));
	}
	return 0;
} 

树状数组

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+6;
#define lowbit(x) x&(-x) 
int sum[maxn],a[maxn];
int n,p,l,r;
void add(int x, int d){ //给位置x增加d
	for(;x<=n;x+=lowbit(x)) sum[x]+=d;
}

void init(){
	n=8;
	for(int i=1;i<=n;i++){
		a[i]=i;
	}
	for(int i=1;i<=n;i++){
		add(i,a[i]);
	}
}

int ask(int x){ //求位置x的前缀和
    int res = 0;
    for(;x;x-=lowbit(x)) res+=sum[x];
    return res;
}

int range_ask(int l, int r){ //区间求和
    return ask(r) - ask(l - 1);
}

int main(){
	init();
	
	return 0;	
} 

模板2

区间修改单点查询

树状数组

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+6;
#define lowbit(x) x&(-x) 
int sum[maxn],a[maxn];
int n,p,l,r;
void add(int x,int d){
	//这个函数用来在树状数组中直接修改
	for(;x<=n;x+=lowbit(x)){
		sum[x]+=d;
	}
}
void range_add(int l,int r,int d){
	//给区间[l, r]加上x
	add(l,d),add(r+1,-d);
}
int query(int x){
	//单点查询(前缀和)
	int res=0;
	for(;x;x-=lowbit(x)){
		res+=sum[x];
	}
	return res;
}
void init(){
	n=8;
	for(int i=1;i<=n;i++){
		a[i]=i;
	}
	for(int i=1;i<=n;i++){
		add(i,a[i]-a[i-1]);
	}
}
int main(){
	init();
	
	return 0;
}

模板3

区间修改+区间查询

线段树(P3打标机)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+2;
int n,m,a[100001];
ll f[400001],v[400001];
inline void bulidtree(int k,int l,int r){
	v[k]=0;
	if(l==r){
		f[k]=a[l];
		return;
	}
	int m=(l+r)>>1;
	bulidtree(k+k,l,m);
	bulidtree(k+k+1,m+1,r);
	f[k]=f[k+k]+f[k+k+1];
}
inline void insert(int k,int l,int r,int s,int t,ll d){
	if(l==s&&r==t){
		v[k]+=d;
		return;
	}
	f[k]+=(t-s+1)*d;
	int m=(l+r)>>1;
	if(t<=m)
		insert(k+k,l,m,s,t,d);
	else if(s>m)
		insert(k+k+1,m+1,r,s,t,d);
	else{
		insert(k+k,l,m,s,m,d),
		insert(k+k+1,m+1,r,m+1,t,d);
	}
}
ll calc(int k,int l,int r,int s,int t,ll p){
	p+=v[k]; 
	if(l==s&&r==t){
		return p*(r-l+1)+f[k];
	}
	int m=(l+r)>>1;
	if(t<=m)
		return calc(k+k,l,m,s,t,p);
	else if(s>m)
		return calc(k+k+1,m+1,r,s,t,p);
	else
		return calc(k+k,l,m,s,m,p)+calc(k+k+1,m+1,r,m+1,t,p);
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	
	bulidtree(1,1,n);
	while(m--){
		int t,x,y;
		ll d;
		scanf("%d",&t);
		if(t==1){
			scanf("%d%d%lld",&x,&y,&d);
			insert(1,1,n,x,y,d);
		}else{
			scanf("%d%d",&x,&y);
			printf("%lld\n",calc(1,1,n,x,y,0));
		}
	}
	
	return 0;
}

线段树优化(单标记下传)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m,a[100001];
ll f[400001],v[400001];
void buildtree(int k,int l,int r){
	v[k]=0;
	if(l==r){
		f[k]=a[l];
		return;
	}
	int m=(l+r)>>1;
	buildtree(k+k,l,m);
	buildtree(k+k+1,m+1,r);
	f[k]=f[k+k]+f[k+k+1];
}
void insert(int k,int l,int r,int x,int y,int d){
	if(l==x&&r==y){
		v[k]+=d;
		return;
	}
	if(v[k])
		v[k+k]+=v[k],v[k+k+1]+=v[k],v[k]=0;
	int m=(l+r)>>1;
	if(y<=m)
		insert(k+k,l,m,x,y,d);
	else if(x>m)
		insert(k+k+1,m+1,r,x,y,d);
	else
		insert(k+k,l,m,x,m,d),insert(k+k+1,m+1,r,m+1,y,d);
	f[k]=f[k+k]+v[k+k]*(m-l+1)+f[k+k+1]+v[k+k+1]*(r-m);
}
ll calc(int k,int l,int r,int x,int y){
	if(l==x&&r==y){
		return f[k]+v[k]*(r-l+1);
	}
	if(v[k])
		v[k+k]+=v[k],v[k+k+1]+=v[k],v[k]=0;
	int m=(l+r)>>1;
	ll res=0;
	if(y<=m)
		res=calc(k+k,l,m,x,y);
	else if(x>m)
		res=calc(k+k+1,m+1,r,x,y);
	else
		res=calc(k+k,l,m,x,m)+calc(k+k+1,m+1,r,m+1,y);
	f[k]=f[k+k]+v[k+k]*(m-l+1)+f[k+k+1]+v[k+k+1]*(r-m);
	return res;
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	buildtree(1,1,n);
	while(m--){
		int t,x,y,d;
		scanf("%d",&t);
		if(t==1){
			scanf("%d%d%d",&x,&y,&d);
			insert(1,1,n,x,y,d);
		}else{
			scanf("%d%d",&x,&y);
			printf("%lld\n",calc(1,1,n,x,y));
		}
	}
	return 0;
}

模板4

线段树双标记下传 (区间操作)

当对区间操作运算超过两种,标记下传,以及更新建议在函数中实现

%%%模板4双标记下传可以涵盖模板1,2,3;

树状数组能完成的操作线段树都可以完成。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int n, m, p, a[100001];
ll f[400001], v[400001], c[400001];

inline void buildtree(int k, int l, int r) {
	v[k] = 0, c[k] = 1;
	if (l == r) {
		f[k] = a[l] % p;
		return;
	}
	int m = (l + r) / 2;
	buildtree(k + k, l, m);
	buildtree(k + k + 1, m + 1, r);
	f[k] = f[k + k] + f[k + k + 1],	f[k] %= p;
}

inline void pushdown(int k, int l, int r) {
	c[k + k] *= c[k], c[k + k] %= p;
	v[k + k] *= c[k], v[k + k] %= p;
	v[k + k] += v[k], v[k + k] %= p;
	c[k + k + 1] *= c[k], c[k + k + 1] %= p;
	v[k + k + 1] *= c[k], v[k + k + 1] %= p;
	v[k + k + 1] += v[k], v[k + k + 1] %= p;
	c[k] = 1, v[k] = 0;
}

inline void update(int k, int l, int r) {
	int m = (l + r) / 2;
	f[k] = f[k + k] * c[k + k] % p + v[k + k] * (m - l + 1) % p + f[k + k + 1] * c[k + k + 1] % p + v[k + k + 1] * (r - m) % p;
	f[k] %= p;
}

inline void mul(int k, int l, int r, int x, int y, int z) {
	if (l == x && r == y) {
		c[k] *= z, c[k] %= p;
		v[k] *= z, v[k] %= p;
		return;
	}
	pushdown(k, l, r);
	int m = (l + r) / 2;
	if (y <= m)
		mul(k + k, l, m, x, y, z);
	else if (x > m)
		mul(k + k + 1, m + 1, r, x, y, z);
	else
		mul(k + k, l, m, x, m, z), mul(k + k + 1, m + 1, r, m + 1, y, z);
	update(k, l, r);
}

inline void add(int k, int l, int r, int x, int y, int z) {
	if (l == x && r == y) {
		v[k] += z, v[k] %= p;
		return;
	}
	pushdown(k, l, r);
	int m = (l + r) / 2;
	if (y <= m)
		add(k + k, l, m, x, y, z);
	else if (x > m)
		add(k + k + 1, m + 1, r, x, y, z);
	else
		add(k + k, l, m, x, m, z), add(k + k + 1, m + 1, r, m + 1, y, z);
	update(k, l, r);
}

int calc(int k, int l, int r, int x, int y) {
	if (l == x && r == y) {
		int res = f[k] * c[k] % p + v[k] * (r - l + 1) % p;
		return res % p;
	}
	pushdown(k, l, r);
	int m = (l + r) / 2;
	int res = 0;
	if (y <= m)
		res = calc(k + k, l, m, x, y);
	else if (x > m)
		res = calc(k + k + 1, m + 1, r, x, y);
	else
		res = calc(k + k, l, m, x, m) + calc(k + k + 1, m + 1, r, m + 1, y), res %= p;
	update(k, l, r);
	return res;
}

int main() {
	scanf("%d%d%d", &n, &m, &p);
	for (int i = 1; i <= n; i++)
		scanf("%d", &a[i]);
	buildtree(1, 1, n);
	for (int i = 1; i <= m; i++) {
		int op;
		scanf("%d", &op);
		if (op == 1) {
			int x, y, z;
			scanf("%d%d%d", &x, &y, &z);
			mul(1, 1, n, x, y, z);
		} else if (op == 2) {
			int x, y, z;
			scanf("%d%d%d", &x, &y, &z);
			add(1, 1, n, x, y, z);
		} else {
			int x, y;
			scanf("%d%d", &x, &y);
			printf("%d\n", calc(1, 1, n, x, y));
		}
	}
	return 0;
}

【模板】可持久化线段树 2

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 1;

struct node {
	int l, r, sum;
} hjt[maxn * 40];
int n, m, cnt = 0, a[maxn], root[maxn];
vector<int> v;

int getid(int x) {
	return lower_bound(v.begin(), v.end(), x) - v.begin() + 1;
}

inline void insert(int l, int r, int pre, int &now, int p) {
	hjt[++cnt] = hjt[pre];
	now = cnt;
	hjt[now].sum++;
	if (l == r)
		return;
	int m = (l + r) >> 1;
	if (p <= m)
		insert(l, m, hjt[pre].l, hjt[now].l, p);
	else
		insert(m + 1, r, hjt[pre].r, hjt[now].r, p);
}

int query(int l, int r, int L, int R, int k) {
	if (l == r)
		return l;
	int m = (l + r) >> 1;
	int temp = hjt[hjt[R].l].sum - hjt[hjt[L].l].sum;
	if (k <= temp)
		return query(l, m, hjt[L].l, hjt[R].l, k);
	else
		return query(m + 1, r, hjt[L].r, hjt[R].r, k - temp);
}

int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++)
		scanf("%d", &a[i]), v.push_back(a[i]);
	sort(v.begin(), v.end());
	v.erase(unique(v.begin(), v.end()), v.end());
	for (int i = 1; i <= n; i++)
		insert(1, n, root[i - 1], root[i], getid(a[i]));
	while (m--) {
		int l, r, k;
		scanf("%d%d%d", &l, &r, &k);
		printf("%d\n", v[query(1, n, root[l - 1], root[r], k) - 1]);
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值