Blue Bridge Cup lesson 5 tree array and line segment tree 2D/3D difference

Posted by winkhere on Wed, 02 Feb 2022 13:12:22 +0100

1, The index of the tree array starts from 1

Operation O(logn)

  1. Single point modification: add a number to the number at a certain position
  2. Interval query: find the sum of a prefix

Offline practice: modification is not supported
Online practice: support modification

principle

Determination of the number of layers: there are several zeros at the end of the binary representation of x
C [x] = (x-lowbit (x), sum of x]
lowbit(x): returns the value corresponding to the lowest 1 in the binary expression of X
lowbit(6) = 2, because the number corresponding to the lowest bit (the second bit from right to left) in (110) 2 is 21 = 2
1264. Dynamic summation of continuous intervals

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 100005;

int a[N],n,m;
int tr[N];//tr[x] represents the sum of (x-lowbit(x),x]
int k,x,y;
int lowbit(int x)
{
    return x & -x;
}
void add(int x,int v) //Add a number to the position of x
{
    for(int i = x;i <= n;i+=lowbit(i))
    {
        tr[i] += v;
    }
}
int query(int x) //Prefix and of query 1~x
{
    int res = 0;
    for(int i = x;i>=1;i-=lowbit(i))
    {
        res += tr[i];
    }
    return res;
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i = 1; i <= n; i ++ ) //Remember to start with subscript 1
    {
        scanf("%d", &a[i]);
        add(i,a[i]);
    }
    while (m -- )
    {
        scanf("%d%d%d",&k,&x,&y);
        if(k==0)
        {
            cout<<query(y) - query(x-1)<<endl; //Prefixes and ideas
        }
        else add(x,y);
    }
    return 0;
}

1265. Counting stars
Since the number of stars below y is greater than or equal to a certain number of stars in the current ascending order, it is required to count the number of stars below y

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 32005;
int n,x,y;
int tr[N];//Number of stars with x coordinate less than or equal to i
int level[N];//Number of stars at different levels
int lowbit(int x)
{
    return x & -x;
}
void add(int t,int x)
{
    for(int i=t;i<=N;i+=lowbit(i)) //Note: the range here is [T, n], the value of X will be greater than N, and WA has sent several rounds
    {
        tr[i] += x;
    }
}
int query(int t)
{
    int sum = 0;
    for(int i=t;i>=1;i-=lowbit(i))
    {
        sum += tr[i];
    }
    return sum;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) //Since the coordinates are given in ascending order of y, the coordinates of the current star must be greater than or equal to any previous stars, so statistics should be less than or equal to the current star
    //The number of stars x is the number of stars at the lower left
    {
        scanf("%d%d", &x, &y);
        x++;//Mapping x to 1~N+1 makes it easy to use the tree array
        level[query(x)]++;
        add(x,1);
    }
    for (int i = 0; i < n; i ++ ) //Note: the range here is 0~n-1, and there can be no stars with level n
    {
        cout<<level[i]<<endl;
    }
    return 0;
}

2, Segment tree

Take interval sum as an example

Core operation O(logn)

1. Single point modification

Modify recursively. As long as the interval contains the points to be modified, modify the sum of the interval

2. Interval query

Query recursively. As long as the [l,r] of the interval is completely contained by the target interval, it will accumulate and backtrack, otherwise continue to query recursively downward.
Query times less than or equal to 4logn

Main function

Push up updates the current node information with the child node information
build initializes the line segment tree on a section
Modify modify
Query query
pushdown lazy flag
1264. Dynamic summation of continuous intervals

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1e5+10;

int n,m,k,a,b;
int w[N];

struct Node
{
    int l;
    int r;
    int sum;
}tr[N*4]; //The maximum number of nodes in the segment tree is 4N

void pushup(int u) //Update the root node information with the left and right child node information
{
    tr[u].sum = tr[2*u].sum + tr[2*u+1].sum;
}

void build(int u,int l,int r) //Formal parameter interpretation: u represents the root node, l and R represent the left and right endpoints of the original data interval
{
    if(l==r) tr[u] = {l,r,w[r]};//The number of interval elements is 1. It is a leaf node. It is returned by direct assignment
    else
    {
        tr[u] = {l,r};//Note: initial value must be assigned here
        int mid = l+r>>1;
        build(u*2,l,mid),build(u*2+1,mid+1,r);//Recursively establish left and right intervals
        pushup(u);//Don't forget to update the sum value of the root node and pass the information up
    }
}
int query(int u,int l,int r)//Formal parameter interpretation: u represents the root node, l and R represent the left and right endpoints of the target interval
{
    if(tr[u].l >= l && tr[u].r <= r) return tr[u].sum; //If the current interval is completely included by the target interval, the current interval sum is returned
    
    int mid = tr[u].l+tr[u].r>>1;
    int sum = 0;
    if(l <= mid) sum += query(u*2,l,r); //If the left boundary of the target interval is ≤ mid, it indicates that there is an intersection with the left half
    if(r > mid) sum += query(u*2+1,l,r);//If the right boundary of the target interval is > mid, it indicates that there is an intersection with the right half
    return sum;
}
void modify(int u,int x,int v) //Formal parameter interpretation: u represents the root node, x represents the element subscript, and v represents the value to be added
{
    if(tr[u].l == tr[u].r) //If you go to the leaf node, it means that you have found the position in the x corresponding tree and can modify it directly
    {
        tr[u].sum += v;
    }
    else
    {
        int mid = tr[u].l + tr[u].r >> 1;
        if(x <= mid) modify(u*2,x,v);//If there is an intersection with the left half, modify it on the left half
        else modify(u*2+1,x,v);//If there is an intersection with the right half, modify it on the right half
        pushup(u);//Note: finally, you must update the root node information with the son node information
    }
}
int main()
{
    scanf("%d%d", &n,&m);
    for(int i = 1;i<=n;i++)
    {
        scanf("%d", &w[i]);
    }
    build(1,1,n);
    while (m -- )
    {
        scanf("%d%d%d",&k,&a,&b);
        if(k==0)
        {
            cout<<query(1,a,b)<<endl;
        }
        else modify(1,a,b);
    }
    return 0;
}

1270. Maximum value of sequence interval

#include <iostream>
#include <cstring>
#include <algorithm>
#include <climits>
using namespace std;

const int N = 1e5 + 10;
int w[N];
int n,m,x,y;
struct Node
{
    int l;
    int r;
    int Max;
}tr[N*4];
inline void build(int u,int l,int r)
{
    if(l==r) tr[u] = {l,r,w[r]};
    else
    {
        tr[u] = {l,r};
        int mid = l+r>>1;
        build(u<<1,l,mid),build(u<<1|1,mid+1,r);
        tr[u].Max = max(tr[u<<1].Max,tr[u<<1|1].Max);
    }
}

inline int query(int u,int l,int r)
{
    if(tr[u].l >= l && tr[u].r <= r) return tr[u].Max;
    
    int Max = INT_MIN;
    int mid = tr[u].l + tr[u].r>>1;
    if(l <= mid) Max = max(Max,query(u<<1,l,r));
    if(r > mid) Max = max(Max,query(u<<1|1,l,r));
    return Max;
}
int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i ++ )
    {
        scanf("%d", &w[i]);
    }
    build(1,1,n);
    while (m -- )
    {
        scanf("%d%d",&x,&y);
        printf("%d\n",query(1,x,y));
    }
    return 0;
}

3, 2D/3D difference

Two dimensional difference


798. Difference matrix

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1005;

int b[N][N];
int n,m,q;

void insert(int x1,int y1,int x2,int y2,int c) //x2,y2 must be increased by 1
{
    b[x1][y1] += c;
    b[x2+1][y2+1] += c;
    b[x1][y2+1] -= c;
    b[x2+1][y1] -= c;
}
int main()
{
    scanf("%d%d%d", &n, &m,&q);
    int c;
    for (int i = 1; i <= n; i ++ )
    {
        for (int j = 1; j <= m; j ++ )
        {
            scanf("%d", &c);
            insert(i,j,i,j,c);
        }
    }
    while (q -- )
    {
        int x1,y1,x2,y2;
        scanf("%d%d%d%d%d", &x1, &y1,&x2,&y2,&c);
        insert(x1,y1,x2,y2,c);
    }
    for (int i = 1; i <= n; i ++ )//Find the prefix sum, that is, the difference matrix is transformed into the original matrix
    {
        for (int j = 1; j <= m; j ++ )
        {
            b[i][j] = b[i-1][j] + b[i][j-1] - b[i-1][j-1] + b[i][j];
        }
    }
    for (int i = 1; i <= n; i ++ )
    {
        for (int j = 1; j <= m; j ++ )
        {
            printf("%d ",b[i][j]);
        }
        puts("");
    }
    return 0;
}

Three dimensional difference

In the formula, for S, the sign of odd minus one is positive and the sign of even minus one is negative

4, Exercises

1215. Children line up
This problem needs to find the number of inverse pairs of each number, and then use the summation formula of the equal difference sequence one by one to calculate the answer. When finding the number of inverse pairs, we need to use the line segment tree

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
typedef long long LL;

const int N = 1e6 + 10;

int h[N],tr[N],n;//The segment tree records the number of each number
int sum[N];
int lowbit(int x)
{
    return x & -x;
}
int query(int p)
{
    int sum = 0;
    for(int i=p;i>=1;i-=lowbit(i))
    {
        sum += tr[i];
    }
    return sum;
}
void add(int p,int x)
{
    for(int i=p;i<=N;i+=lowbit(i))
    {
        tr[i]+=x;
    }
}
int main()
{
    scanf("%d", &n);
    for (int i = 0; i < n; i ++ )
    {
        scanf("%d", &h[i]);
        ++h[i];//To calculate the prefix and, you need to map to 1~N+1
    }
    for(int i=0;i < n;i++) //Find out how many numbers in front of each number are larger than it
    {
        sum[i] += query(N-1) - query(h[i]);
        add(h[i],1);
    }
    memset(tr,0,sizeof tr);//Remember to clear the line segment tree
    for (int i = n-1; i >=0 ; i -- )//Find out how many numbers are smaller after each number
    {
        sum[i] += query(h[i]-1);
        add(h[i],1);
    }
    LL ans = 0;//The answer may explode
    for(int i = 0;i<n;i++)
    {
        //cout<<sum[i]<<" ";
        ans += (LL)(1+sum[i])*sum[i]/2;
    }
    cout << ans<<endl;
    return 0;
}

1228. Paint area

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
typedef long long LL;
const int N = 10005;

int x1,y1,x2,y2,n;
LL ans;
bool g[N][N];
int main()
{
    scanf("%d", &n);
    for (int i = 0; i < n; i ++ )
    {
        scanf("%d%d%d%d", &x1, &y1,&x2,&y2);
        for(int j=x1;j<x2;j++)
        {
            for(int k=y1;k<y2;k++) 
            {
                if(!g[j][k])
                {
                    g[j][k] = 1;
                    ++ans;
                }
            }
        }
    }
    cout << ans << endl;
    return 0;
}

1232. Three body attack

Topics: Algorithm