首页 > 代码库 > POJ 3468 A Simple Problem with Integers(线段树区间修改及查询)
POJ 3468 A Simple Problem with Integers(线段树区间修改及查询)
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 51 2 3 4 5 6 7 8 9 10Q 4 4Q 1 10Q 2 4C 3 6 3Q 2 4
Sample Output
455915
线段树区间查询的核心思想是Lazy原则,顾名思义,懒!!
就是当修改某区间的值是,现将修改的值记录下来,暂不修改。
此时如果查询区间与上一个修改区间没有交集,那么对结果也没有影响。我等用到这个修改过的区间的值时,再将它的值向下更新。
而且只用向下更新一层,因为递归时我们是根据区间的位置情况连续向下找左右子节点的,所以只更新一层就行,更新多了没用(如果更新到底,就变成单点更新了,复杂度爆炸)
代码如下:
1 #include <cstdio> 2 #include <algorithm> 3 4 using namespace std; 5 #define M 100005 6 struct segTree 7 { 8 int l,r; 9 long long int sum,add; 10 int mid() 11 { 12 return (l+r)>>1; 13 } 14 }tree[M<<2]; 15 int n,m; 16 void PushUp (int now)//向上更新:当前节点的sum等于其左右儿子的sum的和 17 { 18 tree[now].sum=tree[now<<1].sum+tree[now<<1|1].sum; 19 } 20 void buildTree (int now,int l,int r) 21 { 22 tree[now].l=l,tree[now].r=r; 23 tree[now].add=0; 24 if (l==r) 25 { 26 scanf("%lld",&tree[now].sum); 27 return; 28 } 29 int m=tree[now].mid(); 30 buildTree(now<<1,l,m);//递归建树 31 buildTree(now<<1|1,m+1,r); 32 PushUp(now);//向上更新 33 } 34 void PushDown (int now,int m) 35 //向下更新:当前节点的add值需要加到自己左右儿子的add与sum上 36 { 37 if (tree[now].add) 38 { 39 tree[now<<1].add+=tree[now].add; 40 tree[now<<1|1].add+=tree[now].add; 41 tree[now<<1].sum+=tree[now].add*(m-(m>>1)); 42 tree[now<<1|1].sum+=tree[now].add*(m>>1); 43 tree[now].add=0; 44 } 45 } 46 void UpDate (int now,int l,int r,int change) 47 //区间[l,r]需要增加值change,now是当前节点 48 { 49 if (tree[now].l==l&&r==tree[now].r) 50 //如果恰好now代表的区间就是更新的区间,一步更新,暂不向下继续更新到其子节点 ,等用到这个节点再向下更新 51 { 52 tree[now].add+=change; 53 tree[now].sum+=(__int64)change*(r-l+1); 54 return ; 55 } 56 if (tree[now].l==tree[now].r) 57 return;//区间长度为1,return 58 PushDown(now,tree[now].r-tree[now].l+1); 59 //用到了当前节点,当前节点向下更新 60 int m=tree[now].mid(); 61 if (r<=m) 62 //==============|==============tree[now]的区间 63 // ******** 要更新的区间 64 UpDate(now<<1,l,r,change); 65 else if (l>m) 66 //==============|==============tree[now]的区间 67 // ******** 要更新的区间 68 UpDate(now<<1|1,l,r,change); 69 else 70 //==============|==============tree[now]的区间 71 // ************* 要更新的区间 72 { 73 UpDate(now<<1,l,m,change); 74 UpDate(now<<1|1,m+1,r,change); 75 } 76 PushUp(now); 77 } 78 long long int query (int now,int l,int r) 79 { 80 if(l==tree[now].l &&r==tree[now].r) 81 { 82 return tree[now].sum; 83 } 84 PushDown(now,tree[now].r-tree[now].l+1);//用到了当前节点,向下更新 85 int m = tree[now].mid(); 86 long long int res = 0; 87 if(r<=m) 88 //==============|==============tree[now]的区间 89 // ******** 要查询的区间 90 res += query(now<<1,l,r); 91 else if(l > m) 92 //==============|==============tree[now]的区间 93 // ******** 要查询的区间 94 res += query(now<<1|1,l,r); 95 //==============|==============tree[now]的区间 96 // ************* 要更新的区间 97 else 98 { 99 res+=query(now<<1,l,m);100 res+=query(now<<1|1,m+1,r);101 }102 return res;103 }104 int main()105 {106 //freopen("de.txt","r",stdin);107 while (~scanf("%d%d",&n,&m))108 {109 buildTree(1,1,n);110 while (m--)111 {112 char op[5];113 scanf("%s",op);114 int x,y,z;115 if (op[0]==‘Q‘)116 {117 scanf("%d%d",&x,&y);118 printf("%lld\n",query(1,x,y));119 }120 else121 {122 scanf("%d%d%d",&x,&y,&z);123 UpDate(1,x,y,z);124 }125 }126 }127 return 0;128 }
POJ 3468 A Simple Problem with Integers(线段树区间修改及查询)