当前位置: 代码迷 >> 综合 >> POJ3468 A Simple Problem with Integers
  详细解决方案

POJ3468 A Simple Problem with Integers

热度:100   发布时间:2023-11-22 01:23:38.0

题目链接

http://poj.org/problem?id=3468

题意

给定由N个整数组成的序列。
对这个序列进行如下两种操作:
(1)Q a b:输出序列第a个元素到第b个元素的和,下标从1开始,包括第a个和第b个
(2)C a b c:对序列第a个元素到第b个元素的所有元素都累加c

题解

线段树区间更新,区间查询问题。
线段树原理:每一个节点代表一个区间上的信息,对区间进行修改,即对若干个对应的节点进行修改。而考虑到暴力修改所有节点的时间复杂度难以接受,所以引入一个延迟标记。也就是说只修改一个节点,而对该节点的子节点暂时不修改,等到下一次需要用到该节点的子节点时(包括更新和修改),再根据延迟标记进行修改。
modify(p,l,r,x,y,z):将区间[x,y]的值都加z
query(p,l,r,x,y):返回区间[x,y]的和
up(p):由下向上更新节点p的值
down(p,l,r):下传延迟标记并修改子节点

代码

#include <cstdio>
#include <cstring>using namespace std;
typedef long long ll;const int maxn=4e5+100;
ll s[maxn],delta[maxn];void down(int p,int l,int r)
{int mid=(l+r)/2;s[p*2]+=(mid-l+1)*delta[p];s[p*2+1]+=(r-mid)*delta[p];delta[p*2]+=delta[p];delta[p*2+1]+=delta[p];delta[p]=0;
}void up(int p)
{s[p]=s[p*2]+s[p*2+1];
}ll query(int p,int l,int r,int x,int y)
{if(x<=l && r<=y){return s[p];}down(p,l,r);int mid=(l+r)/2;ll ret=0;if(x<=mid) ret+=query(p*2,l,mid,x,y);if(y>mid) ret+=query(p*2+1,mid+1,r,x,y);up(p);return ret;
}void modify(int p,int l,int r,int x,int y,int z)
{if(x<=l && r<=y){s[p]+=(r-l+1)*z;delta[p]+=z;return;}down(p,l,r);int mid=(l+r)/2;if(x<=mid) modify(p*2,l,mid,x,y,z);if(y>mid) modify(p*2+1,mid+1,r,x,y,z);up(p);
}int main()
{int N,Q;while(~scanf("%d%d",&N,&Q)){memset(s,0,sizeof(s));memset(delta,0,sizeof(delta));for(int i=1;i<=N;i++){int a;scanf("%d",&a);modify(1,1,N,i,i,a);}while(Q--){char ch;getchar();scanf("%c",&ch);int x,y,z;if(ch=='Q'){scanf("%d%d",&x,&y);printf("%lld\n",query(1,1,N,x,y));}else{scanf("%d%d%d",&x,&y,&z);modify(1,1,N,x,y,z);}}}return 0;
}
  相关解决方案