POJ-3468-A Simple Problem with Integers(线段树 区间修改 区间查询)
A Simple Problem with Integers
Time Limit: 5000MS | Memory Limit: 131072K |
Case Time Limit: 2000MS
Description
You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.
Input
The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1, A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
"C a b c" means adding c to each of Aa, Aa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q a b" means querying the sum of Aa, Aa+1, ... , Ab.
Output
You need to answer all Q commands in order. One answer in a line.
Sample Input
10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4
Sample Output
4
55
9
15
Hint
The sums may exceed the range of 32-bit integers.
Source
POJ Monthly--2007.11.25, Yang Yi
单点修改的时间复杂度 n^2logn
lazy标记 时间复杂度 nlogn 少了对每个结点修改的时间
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
#define MAXN 100000
typedef struct segmentree
{
int left;
int right;
long long sum; //long long 型
long long lazy;
}segmentree;
segmentree segtree[MAXN<<2];
long long a[MAXN]; //有long long型还是要同步long long 型,避免不必要的错误
void push_up(int root)
{
segtree[root].sum = segtree[root<<1].sum + segtree[root<<1|1].sum;
}
void push_down(int root)
{
if(segtree[root].lazy)
{
segtree[root<<1].sum += (segtree[root<<1].right - segtree[root<<1].left + 1)*segtree[root].lazy;
segtree[root<<1|1].sum += (segtree[root<<1|1].right - segtree[root<<1|1].left + 1)*segtree[root].lazy;
segtree[root<<1].lazy += segtree[root].lazy;
segtree[root<<1|1].lazy += segtree[root].lazy;
segtree[root].lazy = 0; //下方lazy的同时就是在修改下面结点的数值,用lazy,可以在不用下面结点时,不对下面结点进行修改
}
}
void CreateSegmentree(int root,int l,int r) //创建线段树
{
segtree[root].left = l;
segtree[root].right = r;
segtree[root].sum = 0;
if(l == r)
segtree[root].sum = a[l];
else
{
int mid = (l+r)>>1;
CreateSegmentree(root<<1,l,mid);
CreateSegmentree(root<<1|1,mid+1,r);
push_up(root);
//递归的终止就是l==r
}
return;
}
long long query_sum(int root,int l,int r) //查询线段树的各个区间。
{
if(segtree[root].left == l && segtree[root].right == r)
return segtree[root].sum;
push_down(root); //相对于单点查询就多了一个push_down.进入子树就代表要下方lazy了
int mid = (segtree[root].left + segtree[root].right) >> 1;
if(r <= mid)
return query_sum(root<<1, l, r);
else if(l > mid)
return query_sum(root<<1|1, l, r);
else
return query_sum(root<<1, l, mid) + query_sum(root<<1|1, mid+1, r);
}
void add(int root,int l,int r,int val) //区间修改,三步操作,要l,r,
{
if(segtree[root].left==l&&segtree[root].right==r)
{
segtree[root].sum += 1LL*(r-l+1)*val; //因为sum是 long long 型的, 而val不是long long 型的 ,所以要有这种强制运算
segtree[root].lazy += val;
return;
}
else
{
int mid= (segtree[root].left + segtree[root].right)>>1;
push_down(root);
if(r <= mid)
add(root<<1, l, r, val);
else if(l > mid)
add(root<<1|1, l, r, val);
else add(root<<1, l, mid, val),add(root<<1|1, mid+1, r, val);
push_up(root);
}
return ;
}
int main()
{
int n,m;
int i;
int l,r,val;
char ops[20];
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
CreateSegmentree(1,1,n);
while(m--)
{
scanf("%s",ops);
if(ops[0]=='Q')
{
scanf("%d%d",&l,&r);
printf("%lld\n",query_sum(1,l,r));
}
else
{
scanf("%d%d%d",&l,&r,&val);
add(1,l,r,val);
}
}
return 0;
}