- 分享
洛谷P3372 70分求调
- 2024-11-24 21:29:16 @
#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 条评论
目前还没有评论...