Foreword
Compared to the tree array segment tree structure data amount of the code block is not too large, and easy to understand,But efficiency is not high。
And because, tree line, contact with the block of Fenwick tree is great, the applicable questions also little difference, so Konjac can also use blockRelaxedHe had lost to the questions.
text
1. references
Obviously, this question is used to modify the interval and range queries (sum), and of course the establishment of tree line
The segment tree, is written like this :( only Tacca wording)
(1) modifying the interval (the amount of code which ...
1 void spread(int t){ //打延迟标记 2 if(tree[t].mark) 3 { 4 tree[t*2].val+=tree[t].mark*(tree[t*2].r-tree[t*2].l+1); 5 tree[t*2+1].val+=tree[t].mark*(tree[t*2+1].r-tree[t*2+1].l+1); 6 tree[t*2].mark+=tree[t].mark; 7 tree[t*2+1].mark+=tree[t].mark; 8 tree[t].mark=0; 9 } 10 } 11 12 void change(int t,int x,int y,int k) //维护线段树 13 { 14 if(x<=tree[t].l && y>=tree[t].r) 15 { 16 tree[t].val+=(long long)k*(tree[t].r-tree[t].l+1); 17 tree[t].mark+=k; 18 return; 19 } 20 spread(t); 21 int mid=tree[t].l+tree[t].r>>1; 22 if(x<=mid) change(t*2,x,y,k); 23 if(y>mid) change(t*2+1,x,y,k); 24 tree[t].val=tree[t*2].val+tree[t*2+1].val; 25 }
(2) query interval
1 long long ask(int t,int x,int y) //查询 2 { 3 if(x<=tree[t].l && y>=tree[t].r) return tree[t].val; 4 spread(t); 5 int mid=tree[t].l+tree[t].r>>1; 6 long long ans=0; 7 if(x<=mid) ans+=ask(t*2,x,y); 8 if(y>mid) ans+=ask(t*2+1,x,y); 9 return ans; 10 }
(3) contribution
1 void bulid(int t,int l,int r) 2 { 3 tree[t].l=l;tree[t].r=r; 4 if(l==r) 5 { 6 tree[t].val=a[l]; 7 return; 8 } 9 int mid=l+r>>1; 10 bulid(t*2,l,mid); //左子树 11 bulid(t*2+1,mid+1,r); //右子树 12 is Tree [T] .val Tree = [T * 2 ] + Tree .val [T * 2 + . 1 ] .val; // find their values obtained after the value of the child 13 }
As can be seen, while maintaining a line of trees, it is very troublesome.
2. On the Block
Now, let's study the practice of sub-blocks.
(1) Block thought of:
The section is divided into several blocks, then segmentation process. Among them, a large segment of maintenance, local simple.
Like on the map, I used the red line range block, blue is the number of elements.
In general, we have a n interval √n elements into blocks, if there is a shortage of the elements to be individually separated into one.
Of course, to deal with different titles, in order to simplify the complexity of the time, divided into a number of blocks also ∛n, n ^ (3/4) $ and so on.
Each block consists of a storage structure, each of the basic structure to include: the left point, right point, interval values.
Wherein range values are different for different topics in terms of numbers, this question, the interval value is the sum of all elements of the interval.
(2) Algorithm Code:
1. Block
Step 1.1:
-
Define the number of blocks t = sqrt (n)
-
To the left end point of each interval, the right end of the assignment;
-
Each recording element belongs to which interval, and its value added value interval.
1.2 Code:
1 void Blocking() 2 { 3 int t=sqrt(n); 4 for(int i=1;i<=t;i++) 5 { 6 blo[i].l=(i-1)*sqrt(n)+1; 7 blo[i].r=i*sqrt(n); 8 } 9 if(blo[t].r<n) 10 { 11 blo[t+1].l=blo[t].r+1; 12 blo[t+1].r=n; 13 } 14 for(int i=1;i<=t+1;i++) 15 for(int j=blo[i].l;j<=blo[i].r;j++) 16 { 17 pos[j]=i; 18 blo[i].val+=a[j]; 19 } 20 }
2. Modify Maintenance
Step 2.1
When the left point and the right end of the same paragraph:
Direct violence modify the value of each element.
When the right end of the left point and the different segments:
The above chart, we have selected closed interval [7,14] [ 7 , . 1 . 4 ] is to be operated.
Within this range, a large segment [9,12] [ 9 , . 1 2 ], and small pieces of [7,8] [ 7 , 8 ], [13, 14] [ . 1 . 3 , . 1 . 4 ]
For a large segment, we have to take the time complexity of the algorithm than simple arithmetic, how to achieve it?
For each section, we add an element to the Add , when the role is to record how much time interval is added to the whole modification (also can be negative), so you do not have to modify each element, simplifying the complexity of the time.
2.2 Code
1 void change(int x,int y,int k) 2 { 3 int p=pos[x]; 4 int q=pos[y]; 5 if(p==q) 6 { 7 for(int i=x;i<=y;i++) 8 a[i]+=k; 9 blo[p].val+=(y-x+1)*k; 10 } 11 else 12 { 13 for(int i=p+1;i<=q-1;i++) 14 blo[i].add+=k; 15 for(int i=x;i<=blo[p].r;i++) 16 a[i]+=k; 17 blo[p].val+=(blo[p].r-x+1)*k; 18 for(int i=blo[q].l;i<=y;i++) 19 a[i]+=k; 20 blo[q].val+=(y-blo[q].l+1)*k; 21 } 22 }
3. Ask
Step 3.1:
To improve the time complexity, we add add elements, so when asked will be more complicated.
When the left point and the right end of the same paragraph:
暴力累加每一个元素的值。
When the right end of the left point and the different segments:
Or this picture, but this time I need to query the value of each number in the interval,
At this time, we modify the same as on the whole and small pieces separately.
The whole: here they had to bring interval values val , and
val some extent the value of the recording interval. However, in the whole range of modifications, we did not modify val value, but modify the add value.
So, we have to put into the calculation val.
Subparagraph: naively added value of each number, plus the interval where the Add .
Q : Why are there plus add it? When the query interval is small pieces rather than the whole.
A : Although the query is small pieces, but in the interval modified, there may be a whole section, only modify the add , so plus add
3.2 Code
1 int ask(int x,int y) 2 { 3 int sum=0; 4 int p=pos[x]; 5 int q=pos[y]; 6 if(p==q) 7 { 8 for(int i=x;i<=y;i++) 9 sum+=a[i]; 10 sum+=(y-x+1)*blo[p].add; 11 } 12 else 13 { 14 for(int i=p+1;i<=q-1;i++) 15 sum+=blo[i].val+(blo[i].r-blo[i].l+1)*blo[i].add; 16 for(int i=x;i<=blo[p].r;i++) 17 sum+=a[i]; 18 sum+=(blo[p].r-x+1)*blo[p].add; 19 for(int i=blo[q].l;i<=y;i++) 20 sum+=a[i]; 21 sum+=(y-blo[q].l+1)*blo[q].add; 22 } 23 return sum; 24 }
AC_ total code:
1 #include<bits/stdc++.h> 2 #pragma GCC optimize(3) 3 #define ll long long 4 using namespace std; 5 struct Block 6 { 7 ll l,r,val,add; 8 }blo[100005]; 9 ll a[100005],pos[100005],n,m,op,x,y,k; 10 void Blocking() 11 { 12 int t=sqrt(n); 13 for(int i=1;i<=t;i++) 14 { 15 blo[i].l=(i-1)*sqrt(n)+1; 16 blo[i].r=i*sqrt(n); 17 } 18 if(blo[t].r<n) 19 { 20 blo[t+1].l=blo[t].r+1; 21 blo[t+1].r=n; 22 } 23 for(int i=1;i<=t+1;i++) 24 for(int j=blo[i].l;j<=blo[i].r;j++) 25 { 26 pos[j]=i; 27 blo[i].val+=a[j]; 28 } 29 } 30 void change(ll x,ll y,ll k) 31 { 32 int p=pos[x]; 33 int q=pos[y]; 34 if(p==q) 35 { 36 for(int i=x;i<=y;i++) 37 a[i]+=k; 38 blo[p].val+=(y-x+1)*k; 39 } 40 else 41 { 42 for(int i=p+1;i<=q-1;i++) 43 blo[i].add+=k; 44 for(int i=x;i<=blo[p].r;i++) 45 a[i]+=k; 46 blo[p].val+=(blo[p].r-x+1)*k; 47 for(int i=blo[q].l;i<=y;i++) 48 a[i]+=k; 49 blo[q].val+=(y-blo[q].l+1)*k; 50 } 51 } 52 ll ask(int x,int y) 53 { 54 ll sum=0; 55 int p=pos[x]; 56 int q=pos[y]; 57 if(p==q) 58 { 59 for(int i=x;i<=y;i++) 60 sum+=a[i]; 61 sum+=(y-x+1)*blo[p].add; 62 } 63 else 64 { 65 for(int i=p+1;i<=q-1;i++) 66 sum+=blo[i].val+(blo[i].r-blo[i].l+1)*blo[i].add; 67 for(int i=x;i<=blo[p].r;i++) 68 sum+=a[i]; 69 sum+=(blo[p].r-x+1)*blo[p].add; 70 for(int i=blo[q].l;i<=y;i++) 71 sum+=a[i]; 72 sum+=(y-blo[q].l+1)*blo[q].add; 73 } 74 return sum; 75 } 76 int main() 77 { 78 std::ios::sync_with_stdio(false); 79 cin>>n>>m; 80 for(int i=1;i<=n;i++) 81 cin>>a[i]; 82 Blocking(); 83 for(int i=1;i<=m;i++) 84 { 85 cin>>op; 86 if(op==1) 87 { 88 cin>>x>>y>>k; 89 change(x,y,k); 90 } 91 else if(op==2) 92 { 93 cin>>x>>y; 94 cout<<ask(x,y)<<endl; 95 } 96 } 97 return 0; 98 }