On the block and LuoguP3372 template [1] tree line solution to a problem

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:

  1. Define the number of blocks  t = sqrt (n)

  2. To the left end point of each interval, the right end of the assignment;

  3. 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 }

 

Guess you like

Origin www.cnblogs.com/chengyurui/p/11297882.html