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

typedef long long ll;

int n,m;

struct node{
  ll l,r,f,w;
};

node tree[5000010];

void down(int k){//有懒标记,修改子节点 见区间加 
  tree[2*k].f+=tree[k].f;//目前只查询子节点,只修改子节点,子节点的以下继续懒(使用+=而不是赋值,原因:可能之前有工作没做完,下次要一起做) 
  tree[2*k+1].f+=tree[k].f;
  tree[2*k].w+=tree[k].f*(tree[2*k].r-tree[2*k].l+1);//刚才区间加没有修改子节点值,现在需要用,修改 
  tree[2*k+1].w+=tree[k].f*(tree[2*k+1].r-tree[2*k+1].l+1); 
  tree[k].f=0;//该节点工作完成,懒标记清零 
} 

void build(int k/*现节点*/,int ll,int rr){//build(1,1,n);
  tree[k].l=ll;/*左界限*/
  tree[k].r=rr;/*右界限*/
  if(tree[k].l==tree[k].r)/*左界限=右界限 意味该点即叶子点 赋值*/{cin>>tree[k].w;return;}
  int mid=(tree[k].l+tree[k].r)/2;
  build(2*k,ll,mid);
  build(2*k+1,mid+1,rr);
  tree[k].w=tree[2*k].w+tree[2*k+1].w;//父亲节点值为两儿子值的和 
}

ll ask_p(int k/*现节点*/,int x/*查找点*/){
  if(tree[k].l==tree[k].r)return tree[k].w;/*左界限=右界限 意味该点即叶子点 读数*/
  if(tree[k].f)down(k);//有懒标记,证明子节点未修改,修改子节点
  int mid=(tree[k].l+tree[k].r)/2;
  if(x<=mid)return ask_p(2*k,x);//若x点在  左--中,从左儿子继续向下查询 
  else return ask_p(2*k+1,x);//若x点在  中--右,从右儿子继续向下查询
} 

void add_p(int k,int x,ll add){//给第x个元素加add
  if(tree[k].l==tree[k].r){tree[k].w+=add;return;}/*左界限=右界限 意味该点即叶子点 修改*/
  if(tree[k].f)down(k);//有懒标记,证明子节点未修改,修改子节点
  int mid=(tree[k].l+tree[k].r)/2;
  if(x<=mid)add_p(2*k,x,add);//若x点在  左--中,从左儿子继续向下查询
  else add_p(2*k+1,x,add);//若x点在  中--右,从右儿子继续向下查询
  tree[k].w=tree[2*k].w+tree[2*k+1].w;//父亲节点值修改
}

ll ask_q(int k,int x,int y){//查询x到y的和 
  if(x<=tree[k].l&&y>=tree[k].r){return tree[k].w;}//若x在左边界左边且y在右边界右边,直接取该节点值
  if(tree[k].f)down(k);//有懒标记,证明子节点未修改,修改子节点
  int ans=0;
  int mid=(tree[k].l+tree[k].r)/2;
  if(x<=mid)ans +=ask_q(2*k,x,y);//若x在  左--中,从左儿子继续向下查询 
  if(y>=mid+1)ans +=ask_q(2*k+1,x,y);//若y在  中--右,从右儿子继续向下查询
  return ans;
}

void add_q(int k,int x,int y,int add){
  if(x<=tree[k].l&&y>=tree[k].r){//若 x到y 包含 左界限到右界限 对整体增加 
    tree[k].w+=add*(tree[k].r-tree[k].l+1);
    tree[k].f+=add;//未修改子节点,记录懒标记 
    return;
  }
  if(tree[k].f)down(k);//有懒标记,证明子节点未修改,修改子节点
  int mid=(tree[k].r+tree[k].l)/2;
  if(x<=mid)add_q(2*k,x,y,add);
  if(y>mid)add_q(2*k+1,x,y,add);
  tree[k].w=tree[2*k].w+tree[2*k+1].w;//父亲节点值修改
return;
}

int main(){
  freopen("P3372_8.in","r",stdin);
  freopen("P3372_8.out","w",stdout);
  cin>>n>>m;
  build(1,1,n);
  /* 输出树,检查 
  int s=2,t=2;
  for(int i=1;i<=5*n;i++){
    cout<<i<<":"<<tree[i].w<<" ";
    if(t==s){cout<<endl;s*=2;int t=1;}
    t++;
  }*/ 
  for(int i=1;i<=m;i++){
    int x;
	cin>>x;
	//if(x==1){int y;cin>>y;cout<<ask_p(1,y);}
	//if(x==2){int y,add;cin>>y>>add;add_p(1,y,add);}
	if(x==2){int fir,las;cin>>fir>>las;cout<<ask_q(1,fir,las)<<endl;}
	if(x==1){int fir,las,add;cin>>fir>>las>>add;add_q(1,fir,las,add);}
	
  }
return 0;
} 

0 条评论

目前还没有评论...