/**
* author: McFly
* created: 02.2022
* describ: 线段树
**/
#include <bits/stdc++.h>
using namespace std;
typedef long long int ll; //要开long long
void tree_build( vector<ll>& v, vector<ll>& array, int left, int right, int pos )
/*
建树,单点插入
left,right 是值在一维数组中下标的左右边界, index是值在数组中下标, pos是线段树某节点对应数组结构中位置下标
*/
{
if( left == right ) {
v[pos] = array[left];
return ;
}
int mid = left + ( (right-left)>>1 ); //>>,<<是右结合的,一定记得套括号
tree_build( v,array,left,mid,pos<<1 ); //左右子树这样写,快捷又高档。
tree_build( v,array,mid+1,right,pos<<1|1 ); //方向别写反了
v[pos] = v[pos<<1] + v[pos<<1|1];
}
ll tree_search( vector<ll>& v, vector<ll>& lazy, int l, int r,
int aim_left, int aim_right, int pos )
/*
区间查询
l,r是当前节点代表的左右边界, aim_left/right是目标区间, pos是线段树节点在v中的下标
*/
{
if( l == aim_left && r == aim_right ) {
return v[pos];
}
int mid = (l+r)>>1;
if( lazy[pos] ) {
lazy[pos<<1] += lazy[pos];
lazy[pos<<1|1] += lazy[pos];
v[pos<<1] += lazy[pos]*(mid-l+1);
v[pos<<1|1] += lazy[pos]*(r-mid);
lazy[pos] = 0;
}
ll ret = 0;
if( aim_left <= mid ) {
ret += tree_search( v,lazy,l,mid,aim_left,min(mid,aim_right),pos*2 );
}
if( aim_right > mid ) {
ret += tree_search( v,lazy,mid+1,r,max(aim_left,mid+1),aim_right,pos*2+1 );
}
//注意这里每次更新目标区间,一定要加min/max把区间写对了
//或者前面特判改成(l<=aim_left&&r>=aim_right),同时下面递归时不改变目标区间
return ret;
}
ll tree_alert( vector<ll>& v, vector<ll>& lazy, int l, int r,
int aim_left, int aim_right, ll k, int pos )
/*
区间修改
参数意义同search,事实上search就是alert的一部分
*/
{
/* 若当前节点区间与待求区间匹配,直接返回本节点值(k乘区间长度) */
if( l == aim_left && r == aim_right ) {
lazy[pos] += k;
v[pos] += (r-l+1)*k;
return v[pos];
}
int mid = l + (r-l)/2;
/* lazy标记下传 */
if( lazy[pos] ) {
lazy[pos<<1] += lazy[pos];
lazy[pos<<1|1] += lazy[pos];
v[pos<<1] += lazy[pos]*(mid-l+1);
v[pos<<1|1] += lazy[pos]*(r-mid);
lazy[pos] = 0;
}
ll lc = v[pos<<1],rc = v[pos<<1|1];
/* 处理子树 */
if( aim_left <= mid ) {
lc = tree_alert( v,lazy,l,mid,aim_left,min(mid,aim_right),k,pos<<1 );
}
if( aim_right > mid ) {
rc = tree_alert( v,lazy,mid+1,r,max(aim_left,mid+1),aim_right,k,pos<<1|1 );
}
/* 子树处理完后更新节点 */
v[pos] = lc+rc;
return v[pos];
}
int main()
{
ios_base::sync_with_stdio(false),cin.tie(0); //cin/cout一定要开这个
int n, m;
cin >> n >> m;
vector<ll> array(n+1); //暂存数组
vector<ll> v(n*4); //线段树
vector<ll> lazy(n*4); //lazy标记 , 注意下标都从1开始(便于左右子树下标的确定)
/* 建树 */
for ( int i = 0; i < n; i++ ) cin >> array[i+1];
tree_build( v, array, 1, n, 1 );
int option,x,y,k;
while( m-- ) {
cin >> option;
/* 1为更新区间值,2为输出区间和 */
if( option == 1 ) {
cin >> x >> y >> k;
tree_alert( v,lazy,1,n,x,y,k,1);
}
else {
cin >> x >> y;
cout << tree_search( v,lazy,1,n,x,y,1 ) << endl;
}
}
}
版权声明:本文为weixin_45665700原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。