ysq20110325 @ 2023-07-17 20:51:52
#include<bits/stdc++.h>
using namespace std;
int n,m;
long long a[1111111],w[4111111],lzy[4111111];
//n—点的个数
//m—边的个数
//a—单个点的点值(数组)
//w—区间和(数组)
//lzy—延迟标记(数组)
//赋值操作
void pushup(const int u){
//u为要赋值的结点
w[u]=w[u*2]+w[u*2+1];//u*2是父节点u的左子树,u*2+1是其的右子树
return;
}
//递归建造线段树
void build(const int u,int l,int r){
//u—当前结点,l—其左子结点,r—其右子结点
if(l==r){//没有子结点,即点u为叶子结点
w[u]=a[l];//赋值
return;
}
int mid=(l+r)/2;//将区间分为左右子区间
build(u*2,l,mid);//递归建立其左子树
build(u*2+1,mid+1,r);//递归建立其右子树
pushup(u);//由其左右子区间更新该区间的和
return;
}
//单点修改操作
void update1(int u,int l,int r,int p,long long x){
//u—当前结点,l—其左子结点,r—其右子结点 p—要修改的结点 x—要修改的值
if(l==r){//到达叶节点直接赋值
w[u]=x;
}else {
int mid=(l+r)/2;//将区间分为左右子区间
if(mid>=p){//如果要修改的位置在左子树的区间,修改左子树
update1(u*2,l,mid,p,x);
}else{
update1(u*2+1,mid+1,r,p,x);//否则修改右子树的区间
}
pushup(u);//更新当前节点的值
}
return;
}
//单点查询操作
long long query1(int u,int l,int r,int p){
//u—当前结点,l—其左子结点,r—其右子结点 p—要查询的结点
if(l==r){//抵达叶结点就返回
return w[u];
}else {
int mid=(l+r)/2;//将区间分为左右子区间
if(mid>=p){
return query1(u*2,l,mid,p);//如果要查询的位置在左子树的区间,就查询左子树的区间
}else{
return query1(u*2+1,mid+1,r,p);//反之查询右子树的区间
}
}
}
//判断一个子区间是否被另一个完全包含
bool inrange(int l1,int r1,int l2,int r2){
//l1—一个子区间的左端点 r1—一个子区间的右端点 l2—另一个子区间的左端点 r2—另一个子区间的右端点
return(l2<=l1)&&(r1<=r2);//判断[l1,r1]是否被[l2,r2]完全包含
}
//判断一个子区间是否完全与另一个无交
bool outofrange(int l1,int r1,int l2,int r2){
//l1—一个子区间的左端点 r1—一个子区间的右端点 l2—另一个子区间的左端点 r2—另一个子区间的右端点
return (l1>r2)||(r1<l2);//判断[l1,r1]是否与[l2,r2]完全无交
}
//区间查询操作
long long query2(int u,int l1,int r1,int l2,int r2){
//u—当前结点,l1—其左子结点,r1—其右子结点 l2—要查询的区间的左端点 r2—要查询的区间的右端点
if(inrange(l1,r1,l2,r2)){//如果被完全包含就返回该区间区间和
return w[u];
}else if(!outofrange(l1,r1,l2,r2)){//如果有区间局部被包含了
int mid=(l1+r1)/2;//将区间分为左右子区间
return query2(u*2,l1,mid,l2,r2)+query2(u*2+1,mid+1,r1,l2,r2);//返回左右子区间中包含目标区间中的元素的值的和
}else return 0;//否则一定完全无交
}
//放置延迟标记
void maketag(int u,int len,long long x){
//u—要放置延迟标记的结点 len—要在u结点的子区间内放置延迟标记的结点个数 x—要放置的延迟标记的值
lzy[u]+=x;//修改当前结点的延迟标记
w[u]+=len*x;//修改当前结点的区间和
return;
}
//把延迟标记放置到下一层
void pushdown(int u,int l,int r){
//u—当前结点,l—其左子结点,r—其右子结点
int mid=(l+r)/2;//将区间分为左右子区间
maketag(u*2,mid-l+1,lzy[u]);//为u结点的左子树加上延迟标记
maketag(u*2+1,r-mid,lzy[u]);//为u结点的右子树加上延迟标记
lzy[u]=0;//延迟标记以传至下一层,清空当前层的延迟标记
return;
}
//区间修改
void update2(int u,int l1,int r1,int l2,int r2,long long x){
//l1—一个子区间的左端点 r1—一个子区间的右端点 l2—要修改的子区间的左端点 r2—要修改的子区间的右端点 x—要修改的值
if(inrange(l1,r1,l2,r2)){//如果完全被包含
maketag(u,r1-l1+1,x);//直接给该区间打上延迟标记
}else if(!outofrange(l1,r1,l2,r2)){
int mid=(l1+r1)/2;//将区间分为左右子区间
pushdown(u,l1,r1);//下传延迟标记
update2(u*2,l1,mid,l2,r2,x);//递归修改以为u结点的左子树
update2(u*2+1,mid+1,r1,l2,r2,x);//递归修改以为u结点的右子树
pushup(u);//修改u
}
return;
}
int main(){
cin.tie(0);
cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
build(1,1,n);//建立线段树
for(int t=1;t<=m;t++){
int op,x,y;
long long k=0;
cin>>op;//表示操作(修改/查询)
if(op==1){//如果要修改区间
//x—要修改的子区间的左端点 y—要修改的子区间的右端点 k—增加的值
cin>>x>>y>>k;
update2(1,1,n,x,y,k);
}else {//否则查询区间和
//x—要查询的区间的左端点 y—要查询的区间的右端点
cin>>x>>y;
cout<<query2(1,1,n,x,y)<<endl;
}
}
return 0;
}
by ysq20110325 @ 2023-07-17 20:53:54
一组hack: 8 10 640 591 141 307 942 58 775 133 2 1 5 2 3 8 2 3 6 2 5 8 2 4 8 1 4 8 60 2 1 6 2 5 8 1 3 7 15 1 2 6 86
by ysq20110325 @ 2023-07-17 20:55:35
倒数第二次询问期望2859,输出2739
by ysq20110325 @ 2023-07-17 20:56:34
完整答案应为:2621 2356 1448 1908 2215 2859 2148
by xun_xun @ 2023-07-18 06:49:49
区间查询要pushdown吧
by xun_xun @ 2023-07-18 06:50:17
@ysq20110325
by xun_xun @ 2023-07-18 06:56:04
懒标记原理是要用的时候用,而查询正是要用的时候,我认为查询要写在pushdown下面,在调用自己之前先将当前结点进行pushdown操作
如我的代码:
long long ask(int l,int r,int rt)
{
if(tr[rt].l>r or tr[rt].r<l) return 0;
if(tr[rt].l>=l and tr[rt].r<=r) return tr[rt].sum;
pushdown(rt);
return ask(l,r,rt*2)+ask(l,r,rt*2+1);
}
by xun_xun @ 2023-07-18 07:02:52
我手动修改后可以过楼上的数据,提交能不能AC我不知道
by xun_xun @ 2023-07-18 07:06:08
楼主代码区间查询部分(已删除注释):
long long query2(int u,int l1,int r1,int l2,int r2){
if(inrange(l1,r1,l2,r2)){
return w[u];
}else if(!outofrange(l1,r1,l2,r2)){
int mid=(l1+r1)/2;
pushdown(u,l1,r1);
return query2(u*2,l1,mid,l2,r2)+query2(u*2+1,mid+1,r1,l2,r2);
}else return 0;
}
by ysq20110325 @ 2023-07-18 08:48:49
@xun_xun 以能通过,谢谢大佬