A Simple Problem with Integers POJ - 3468 线段树之区间增加和区间求和,longlong型

You have N integers, A1A2, ... , 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 A1A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
"C a b c" means adding c to each of AaAa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q a b" means querying the sum of AaAa+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.
 
题意:有n个整数,你需要执行两种操作 第一种:Q a b 。表示查询从a到b的所有数的和,第二种:C a b c 。表示把从a到b的所有数都加上c包括a和b。你需要按顺序给出所有查询的语句。
输入:第一行n ,q,来表示有n个数,q表示有多少个语句1<=n,q<=100000.第二行为n个数的初始数值:A1,A2,A3,,,,An,-100000000<=Ai<=100000000.接下来是q个查询语句。注意结果的总和可能超过32为整数
 
思路:线段树的模板,用到了区间加和,懒惰标记,和区间求和,比较注意的 是数比较大,所以我用的是longlong,
 
代码:
  1 #include <cstdio>
  2 #include <fstream>
  3 #include <algorithm>
  4 #include <cmath>
  5 #include <deque>
  6 #include <vector>
  7 #include <queue>
  8 #include <string>
  9 #include <cstring>
 10 #include <map>
 11 #include <stack>
 12 #include <set>
 13 #include <sstream>
 14 #include <iostream>
 15 #define mod 998244353
 16 #define eps 1e-6
 17 #define ll long long
 18 #define INF 0x3f3f3f3f
 19 using namespace std;
 20 
 21 struct node
 22 {
 23     //l表示左边,r表示右边,sum表示该线段的值
 24     ll l,r,sum;
 25     ll lazy;
 26 };
 27 node no[600000];
 28 //存放每个点的值
 29 ll number[100000];
 30 
 31 inline void update(int k)
 32 {
 33     //用左右线段的值更新该线段的值
 34     no[k].sum=no[k*2].sum+no[k*2+1].sum;
 35 }
 36 //初始化
 37 //k表示当前节点的编号,l表示当前区间的左边界,r表示当前区间的右边界
 38 void build(ll k,ll l,ll r)
 39 {
 40     no[k].lazy=0;
 41     no[k].l=l;
 42     no[k].r=r;
 43     //如果递归到最低点
 44     if(l==r)
 45     {
 46         //赋值并记录该点对应的节点编号
 47         no[k].sum=number[l];
 48         return ;
 49     }
 50     //对半分
 51     ll mid=(l+r)/2;
 52     //递归到左线段
 53     build(k*2,l,mid);
 54     //递归到右线段
 55     build(k*2+1,mid+1,r);
 56     update(k);
 57 }
 58 void pushdown(ll k)
 59 {
 60     //如果节点k已经是叶节点了,没有子节点,那么标记就不用下传,直接删除就可以了
 61     if(no[k].l==no[k].r)
 62     {
 63         no[k].lazy=0;
 64         return ;
 65     }
 66     //给k的子节点重新赋值
 67     no[k*2].sum+=(no[k*2].r-no[k].l+1)*no[k].lazy;
 68     no[k*2+1].sum+=(no[k*2+1].r-no[k*2+1].l+1)*no[k].lazy;
 69     //下传点k的标记
 70     no[k*2].lazy+=no[k].lazy;
 71     no[k*2+1].lazy+=no[k].lazy;
 72     //清空点k的标记
 73     no[k].lazy=0;
 74 }
 75 
 76 void change(ll k,ll l,ll r,ll x)
 77 {
 78         //如果当前节点被打上了懒惰标记,那么就把这个标记下传,
 79     if(no[k].lazy)
 80     {
 81         pushdown(k);
 82     }
 83 
 84     if(no[k].l==l&&no[k].r==r)
 85     {
 86         no[k].sum+=(r-l+1)*x;
 87         no[k].lazy+=x;
 88         return ;
 89     }
 90 
 91     ll mid = (no[k].l+no[k].r)/2;
 92     if(r<=mid)
 93     {
 94         change(k*2,l,r,x);
 95     }
 96     else if(l>mid)
 97     {
 98         change(k*2+1,l,r,x);
 99     }
100     else
101     {
102         change(k*2,l,mid,x);
103         change(k*2+1,mid+1,r,x);
104     }
105     update(k);
106 }
107 
108 //查询指定区间内的所有的和
109 //k表示当前节点的编号,l表示当前区间的左边界,r表示当前区间的右边界
110 ll query(ll k,ll l,ll r)
111 {
112     //如果当前区间就是询问区间,完全重合,那么显然可以直接返回
113     if(no[k].l==l&&no[k].r==r)
114     {
115         return no[k].sum;
116     }
117     //如果当前节点被打上了懒惰标记,那么就把这个标记下传,
118     if(no[k].lazy)
119     {
120         pushdown(k);
121     }
122     //取中值
123     ll mid = (no[k].l+no[k].r)/2;
124     //如果询问区间包含在左子区间中
125     if(r<=mid)
126     {
127         return query(k*2,l,r);
128     }
129     else if(l>mid)//如果询问区间包含在右子区间中
130     {
131         return query(k*2+1,l,r);
132     }
133     else//如果询问区间跨越两个子区间
134     {
135         return query(k*2,l,mid)+query(k*2+1,mid+1,r);
136     }
137 }
138 
139 int main()
140 {
141     ll m,n;
142     scanf("%I64d %I64d",&m,&n);
143     for(ll i=1;i<=m;i++)
144     {
145         scanf("%I64d",&number[i]);
146     }
147     build(1,1,m);
148     char str[2];
149     ll a,b,c;
150     while(n--)
151     {
152         cin>>str;
153         if(str[0]=='Q')
154         {
155             scanf("%I64d %I64d",&a,&b);
156             printf("%I64d\n",query(1,a,b));
157         }
158         else if(str[0]=='C')
159         {
160             scanf("%I64d %I64d %I64d",&a,&b,&c);
161             change(1,a,b,c);
162         }
163     }  
164 }

 

posted @ 2019-10-30 21:26  木子川  阅读(127)  评论(0编辑  收藏  举报