Test instructions: is a sequence that supports the query interval and the number within the interval plus C.
Recursive line segments The tree is very good to write, do not speak.
Recursive version: Memory: 6500K time: 2.6 seconds
Non-recursive version one: Memory: 4272K Time: 1.1 seconds
Non-recursive version two: Memory: 4272K Time: 1.3 seconds
--------------------------------------------------------------------------------------------------------------- ---------------------------
-----------------------non-recursive ideas are from Zhang Kunwei's ppt "Power of Statistics"----------------------------
--------------------------------------------------------------------------------------------------------------- ---------------------------
Look at the same as the "power of statistics" of the same ppt, want to try the non-recursive line of the section tree interval modification and summation, and then find this question to test.
Method one (differential and sum):
The main idea is to first set the sequence difference, minus the previous number per number. Then, the original number becomes the prefix of the new series and.
The original prefix and it becomes the prefix and prefix of the new series.
Use s[i] to denote a[1]+a[2]+...+a[i], with P[i] for A[1]+2*a[2]+3*a[3]+...+i*a[i]
Prefix and prefix and ss[x]=s[1]+s[2]+s[3]+...+s[x]=n*a[1]+ (n-1) *a[2] +...+2*a[x-1] + a[x] = (n+1) s[x]-p[x]
So as long as the differential sequence maintenance s[i] and P[i] Two properties are good.
Since the array becomes a relative value, the interval [l,r] plus C, just add the value of L to C and subtract the value of r+1 from C. That is, the interval modification is simplified to a point modification.
So the code is very good to write.
The code S[i] only for a[i] This item, to s[i] to the prefix and to get the above formula S[i].
The code P[i] only for i*a[i] This item, to p[i] to the prefix and to get the above formula P[i].
The last interval and [L,r] is to ask for two SS re-subtraction (Ss[r]-ss[l-1]).
Method Two (Tag permanence):
The power of statistics only gave a brief description of the method, and thought for a long time to figure out how to achieve it.
The idea is that, since non-recursive queries are bottom-up and cannot be tagged, they simply do not pass the tag (that is, the tag is permanently).
Instead of changing to the query interval in the process of meeting the tag to update the answer, had never known how to do this, the recent time to look back to think.
This requires the add tag and the sum tag (the sum tag of the node does not take into account the add of this node).
Interval query:
The interval query process of s and T is the same as when they become the left and right subtree of the same tree, and if S is the S^1 node, add the value of the nodes, and if T is the node, the value of the T^1 node is added.
Now with the tag, notice that the mark on the tree s in each for loop is valid for the leaf node of S, and all the nodes that have been computed on this side are the subtree of S.
So we just need to record the number of nodes that have been counted on this side. LN can update the left answer by tag. The other side of T is the same.
The For loop does not end there, it also needs to handle the tokens of S and T at this point, and then the tokens on all the common ancestors of S and T.
a small problem: The add tag above the interval segment is resolved here, what about the tags below these intervals?
For example, an add tag is only added to an element (non-recursive interval tagging is bottom-up, so the top layer does not know the tag below),
However, when the interval query is for the whole query, the non-recursive query will directly query the above interval, ignoring the following markup.
The answer is that the following tag information is stored in sum, so the interval modification also needs to modify the sum of all ancestors affected by the modified segment (in fact, there is not much to modify).
Use sum to know how many of the nodes below the node have been Add.
In other words, add is added directly to the required interval, and then all the affected sums are processed up.
interval modification: update all changed add and sum from the bottom up
The overall frame of the modification is the same as the query.
Core idea: In each for loop, the s tag represents all the numbers that have been processed on this side of the s, and the s^1 tag is the data that needs to be modified (in the interval modification) or added (in the interval summation).
After modifying or calculating s^1, do not forget to update the value of the number of nodes that have been counted ln.
At the end of the For loop, the S,T nodes are processed separately, and all the common ancestors of s and T are processed.
Small summary:
The first method is a little bit faster than the second one, it's a little bit simpler to write, but the limitations are larger, and there's no way to change the maximum minimum value of the interval, or to change the number of an interval to C.
The second method is more conventional, the same idea can support more markup maintenance, can handle the number of an interval to modify the operation of C, and the definition of the array is also the same as the recursive segment tree (sum and add).
I feel I am not concise enough to write, the second method should also be optimized.
Code:
Here is the core code for the first method (differential and then prefix and prefix and):
#define LL Long long#define maxn 100001LL s[maxn<<2]; LL ss[maxn<<2];int n,q,x;void pushup (int X) {//Update s[x]=s[x<<1]+s[x<<1|1]; P[X]=P[X<<1]+P[X<<1|1];} void Init () {//init before N assignment x=1;while (x <n+2) X <<=1;//calculates offset for (int i=1;i<=n;++i) scanf ("%lld", &s[x +i]);//Read N number s[x]=p[x]=0;for (int i=n+1;i<x;++i) s[x+i]=0; for (int i=x-1;i>0;--i) s[x+i]-=s[x+i-1];//differential for (int i=1;i<x;++i) p[x+i]=s[x+i]*i; Calculate pfor (int i=x-1;i>0;--i) pushup (i);//Build}void INC (LL l,ll r,ll C) {//Interval modification simplifies to point modified int s=x+l,t=x+r+1; S[s]+=c; S[t]-=c; P[s]+=c*l; p[t]-=c* (r+1), while (s^1) s>>=1,pushup (s), while (t^1) t>>=1,pushup (t);} ll QUE (ll R) {//prefix and LL sump=0,sums=0;for (int t=x+r+1;t^1;t>>=1) {if (t&1) sump+=p[t^1],sums+=s[t^1];} Return (r+1) *sums-sump;}
The second method (token persistence):
#define LL Long long#define maxn 100001LL sum[maxn<<2]; LL add[maxn<<2];int n,q,x;void init () {//init prior to assigning N x=1;while (x <n+2) X <<=1; memset (add,0,sizeof (add)); for (int i=1;i<=n;++i) scanf ("%lld", &sum[x+i]); sum[x]=0;for (int i=n+1;i<x;++i) sum[x+i]=0; for (int i=x-1;i>0;--i) sum[x]=sum[x << 1] + sum[x << 1 | 1];} ll QUE (int l,int R) {//interval sum int s=x+l-1,t=x+r+1;//leaf node int ln=0,rn=0,x=1;//left and right branches, and the number of elements per tree LL ans=0;//If it is a set tag, Can add left and right Ans separate sum for (; S^t^1;s >>= 1,t >>= 1,x <<= 1) {//Read tag update if (Add[s]) ans+=add[s]*ln;if (add[t]) ans+= add[t]*rn;//the regular sum if (~s&1) ans+=sum[s^1]+x*add[s^1],ln+=x;if (t&1) ans+=sum[t^1]+x*add[t^1],rn+=x;} Handling of the same layer if (Add[s]) ans+=add[s]*ln;if (add[t]) ans+=add[t]*rn;s>>=1; ln+=rn;//processing upper case for (; s^1;s>>=1) if (Add[s]) Ans+=add[s]*ln;return Ans;} void INC (int l,int r,int C) {//interval +cint s=x+l-1,t=x+r+1;//leaf node int ln=0,rn=0,x=1;//The dot number of the left and right branches, and the number of elements per tree for (; S^t^1;s >> = 1,t >>= 1,x <<= 1) {//Process FirstSum sum[s]+= (LL) c*ln;sum[t]+= (LL) c*rn;//re-process addif (~s&1) add[s^1]+=c,ln+=x;if (t&1) add[t^1]+=c,rn+=x;} Treatment of the same layer sum[s]+= (LL) c*ln;sum[t]+= (LL) c*rn;s>>=1; ln+=rn;//processing upper for (; s^1;s>>=1) sum[s]+= (LL) C*ln;}
Two implementations of interval summation of non-recursive segment tree intervals (take POJ 3468 as an example)