线段树求调2
  • 板块学术版
  • 楼主WD2c0mP
  • 当前回复5
  • 已保存回复5
  • 发布时间2023/2/17 20:24
  • 上次更新2023/10/24 00:33:38
查看原帖
线段树求调2
780641
WD2c0mP楼主2023/2/17 20:24

线段树1求调……

#include <bits/stdc++.h>
#define int long long
using namespace std;
int f[400010],a[400010],tag[400010];
void maketag(int u,int len,int x) { //节点 区间长度 值 
	tag[u] += x;
	f[u] += len * x;
}
void pushdown(int u,int l,int r) { //树里的点 管辖区间左右端点 
	int mid = (l + r) >> 1;
	maketag(u + u,mid - l + 1,tag[u]); //懒标记下放 
	maketag(u + u + 1,r - mid,tag[u]);
	tag[u] = 0;
}
void buildtree(int u,int l,int r) { //建树 
	if (l == r) {
		f[u] = a[l];
		return ;
	}
	int mid = (l + r) >> 1;
	buildtree(u + u,l,mid);
	buildtree(u + u + 1,mid + 1,r);
	f[u] = f[u + u] + f[u + u + 1];
}
bool inrange(int l,int r,int ll,int rr) {
	//判断[l,r]是否被[ll,rr]包含
	return (l <= ll) && (r >= rr); 
} 
bool outofrange(int l,int r,int ll,int rr) {
	//判断[l,r]是否和[ll,rr]完全不相交
	return (r < ll) || (l > rr); 
}
int query(int u,int l1,int r1,int l2,int r2) { //当前节点 管辖区间左端点 右端点 查询左端点 右端点 
	if (inrange(l1,r1,l2,r2)) return f[u]; //如果被包含直接返回区间和
	else if (!outofrange(l1,r1,l2,r2)) {
		int mid = (l1 + r1) >> 1;
		pushdown(u,l1,r1); //先下放懒标记
		return query(u + u,l1,mid,l2,r2) + query(u + u + 1,mid + 1,r1,l2,r2); 
	} else return 0; //完全不相交 
}
void update(int u,int l1,int r1,int l2,int r2,int val) { //当前节点 管辖区间左端点 右端点 修改左端点 右端点 值 
	if (inrange(l1,r1,l2,r2)) maketag(u,r1 - l1 + 1,val); //完全包含就直接打标记
	else if (!outofrange(l1,r1,l2,r2)) {  
		int mid = (l1 + r1) >> 1;
		pushdown(u,r1,r2); //懒标记下放
		update(u + u,l1,mid,l2,r2,val);
		update(u + u + 1,mid + 1,r1,l2,r2,val);
		f[u] = f[u + u] + f[u + u + 1]; 
	}
}
signed main(){
	int n,m;
	cin >> n >> m;
	for (int i = 1;i <= n;i ++) cin >> a[i];
	buildtree(1,1,n);
	while (m --) {
		int op,x,y,z;
		cin >> op;
		if (op == 1) {
			cin >> x >> y >> z;
			update(1,1,n,x,y,z);
		} else {
			cin >> x >> y;
			cout << query(1,1,n,x,y) << endl;
		}
	}
	return 0;
}
2023/2/17 20:24
加载中...