A Simple Problem with Integers

A Simple Problem with Integers
Time Limit:5000MS     Memory Limit:131072KB     64bit IO Format:%I64d & %I64u
Submit  Status  Practice  POJ 3468

Description

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 abc" means adding c to each of AaAa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q ab" 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.
区间更新;
  1 #include<iostream>
  2 #include<cstdio>
  3 
  4 using namespace std;
  5 
  6 #define N 210000
  7 
  8 struct node
  9 {
 10     long long l, r, sum, op, e;  // op 代表是否更新,e代表要更新的数是多少
 11     int len(){return (r-l+1);}  // 区间长度
 12 }tree[N*4];
 13 
 14 long long cnt[N];
 15 
 16 void Build(int root, int l, int r)
 17 {
 18     tree[root].l = l;
 19     tree[root].r = r;
 20     tree[root].op = -1;  // 初始化全部不需要更新
 21     tree[root].e = 0;   // 需要加的值为0
 22 
 23     if(tree[root].l == tree[root].r) 
 24     {
 25         tree[root].sum = cnt[l];  // 到叶子节点时总和就是自身
 26         return ;
 27     }
 28     Build(2*root, l, (l+r)/2);
 29     Build(2*root+1, (l+r)/2+1, r);
 30     tree[root].sum = tree[root*2].sum + tree[root*2+1].sum;  // 这棵树上的和等于左儿子和右儿子的总和
 31 }
 32 
 33 void Down(int root)  // 向下更新
 34 {
 35     if(tree[root].op && tree[root].l != tree[root].r)
 36     {
 37         tree[root].op = false;
 38 
 39         tree[root*2].op = tree[root*2+1].op = true;
 40         tree[root*2].e += tree[root].e;
 41         tree[root*2+1].e += tree[root].e;
 42 
 43         tree[root*2].sum += tree[root].e*tree[root*2].len();
 44         tree[root*2+1].sum += tree[root].e*tree[root*2+1].len();
 45 
 46         tree[root].e = 0;
 47 
 48     }
 49 }
 50 
 51 void update(int root, int a, int b, int e)
 52 {
 53     Down(root); // 每次都可能会向下更新
 54 
 55     tree[root].sum += (b-a+1)*e;  // 这棵树上要家的值是a~b的长度乘以每一个数要加的e,因为这棵树上肯定包括这个区间(否则不会到这棵树上,所以这棵树上的总和要加上
 56 
 57     if(tree[root].l == a && tree[root].r == b)  // 如果这颗树上所有的数都要加数,更新,那么就把这颗树上的op置为1,意味着下边的树要更新,要向下Down,同时就不要向下update了,直接return就行
 58     { 
 59         tree[root].e = e;  // 这棵树上要更新的值为e
 60         tree[root].op = true;
 61         return ;
 62     }
 63     int mid = (tree[root].l+tree[root].r)/2;
 64 
 65     if(b <= mid)
 66         update(2*root, a, b, e);
 67     else if(a > mid)
 68         update(2*root+1, a, b, e);
 69     else
 70     {
 71         update(2*root, a, mid, e);
 72         update(2*root+1, mid+1, b, e);
 73     }
 74 
 75     tree[root].sum = tree[root*2].sum + tree[root*2+1].sum;  // 树上总和等于两个儿子总和
 76 }
 77 
 78 long long query(int root, int l, int r)  // 计算l~r的和
 79 {
 80     if(tree[root].l == l && tree[root].r == r) 
82
return tree[root].sum;
84
85 Down(root); //如果需要也要向下更新 86 87 int mid = (tree[root].l+tree[root].r)/2; 88 89 if(r <= mid) 90 return query(2*root, l, r); 91 else if(l > mid) 92 return query(2*root+1, l, r); 93 return query(root*2, l, mid)+query(root*2+1, mid+1, r); 94 } 95 int main() 96 { 97 long long n, q, a, b, c; 98 char s[9]; 99 100 while(scanf("%lld%lld", &n, &q) != EOF) 101 { 102 for(int i = 1; i <= n; i++) 103 scanf("%lld", &cnt[i]); 104 105 Build(1, 1, n); 106 107 while(q--) 108 { 109 scanf("%s", s); 110 111 if(s[0] == 'Q') 112 { 113 scanf("%lld%lld", &a, &b); 114 printf("%lld\n", query(1, a, b)); 115 } 116 else if(s[0] =='C') 117 { 118 scanf("%lld%lld%lld", &a, &b, &c); 119 update(1, a, b, c); 120 } 121 } 122 } 123 return 0; 124 }

 也可以这么做:www.cnblogs.com/alihenaixiao/p/4611575.html

解题思路:

  线段树更新到每一个节点的话,由于节点数目和查询次数原因会tle,所以在每一个节点内定义一个标志变量表示当前节点的下一层为更新,每次查询时候有需要的话在更新到下一层。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 using namespace std;
  6 const int maxn = 400010;
  7 const int INF = 0x3f3f3f3f;
  8 #define LL __int64
  9 struct node
 10 {
 11     LL L, R;
 12     LL sum, add;
 13     LL Mid()
 14     {
 15         return (L + R) / 2;
 16     }
 17 };
 18 node tree[maxn];
 19 LL res;
 20 
 21 void build(LL root, LL l, LL r)
 22 {
 23     tree[root].L = l;
 24     tree[root].R = r;
 25     tree[root].sum = tree[root].add = 0;
 26 
 27     if (l == r)
 28         return ;
 29     build (2*root+1, l, tree[root].Mid());
 30     build (2*root+2, tree[root].Mid()+1, r);
 31 }
 32 void insert (LL root, LL s, LL e, LL x)
 33 {
 34     tree[root].sum += x * (e - s + 1);
 35     if (tree[root].L == s && e == tree[root].R)//更新到区间
 36         {
 37             tree[root].add += x;
 38             return ;
 39         }
 40     if (e <= tree[root].Mid())
 41         insert (2*root+1, s, e, x);
 42     else if (tree[root].Mid() < s)
 43         insert (2*root+2, s, e, x);
 44     else
 45     {
 46         insert (2*root+1, s, tree[root].Mid(), x);
 47         insert (2*root+2, tree[root].Mid()+1, e, x);
 48     }
 49 }
 50 void query (LL root, LL s, LL e)
 51 {
 52 
 53     if (tree[root].L == s && e == tree[root].R)
 54     {
 55         res += tree[root].sum;
 56         return ;
 57     }
 58     if (tree[root].add)
 59     {//向下继续更新
 60         tree[2*root+1].add += tree[root].add;
 61         tree[2*root+2].add += tree[root].add;
 62         tree[2*root+1].sum += tree[root].add * (tree[2*root+1].R - tree[2*root+1].L + 1);
 63         tree[2*root+2].sum += tree[root].add * (tree[2*root+2].R - tree[2*root+2].L + 1);
 64         tree[root].add = 0;
 65     }
 66     if (e <= tree[root].Mid())
 67         query (2*root+1, s, e);
 68     else if (tree[root].Mid() < s)
 69         query (2*root+2, s, e);
 70     else
 71     {
 72         query (2*root+1, s, tree[root].Mid());
 73         query (2*root+2, tree[root].Mid()+1, e);
 74     }
 75 }
 76 int main ()
 77 {
 78     LL n, m, num;
 79     while (scanf ("%I64d %I64d", &n, &m) != EOF)
 80     {
 81         build (0, 1, n);
 82         for (int i=1; i<=n; i++)
 83         {
 84             scanf ("%I64d", &num);
 85             insert (0, i, i, num);
 86         }
 87         char str[2];
 88         LL s, e;
 89         while (m --)
 90         {
 91             scanf ("%s %I64d %I64d", str, &s, &e);
 92             if (str[0] == 'Q')
 93             {
 94                 res = 0;
 95                 query (0, s, e);
 96                 printf ("%I64d\n", res);
 97             }
 98             else
 99             {
100                 scanf ("%I64d", &num);
101                 insert (0, s, e, num);
102             }
103         }
104     }
105     return 0;
106 }

 

转载于:https://www.cnblogs.com/Tinamei/p/4699947.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值