Differential (one-dimensional, two-dimensional, three-dimensional) blue bridge cup three-body attack

If there is no problem with one-dimensional and two-dimensional, you can jump directly

1D difference

First given an original array a: a[1], a[2], a[3], a[n];
then we construct an array b: b[1] ,b[2] , b[3], b[i];
make a[i] = b[1] + b[2] + b[3] +, + b[i]

The a array is the prefix and array of the b array, and in turn we call the b array the differential array of the a array.

Consider
the most direct way to construct a differential b array
as follows:
a[0]= 0;
b[1] = a[1] - a[0];
b[2] = a[2] - a[1];
b[ 3] = a [3] - a[2];

b[n] = a[n] - a[n-1];
There is an array of b, and through the prefix and operation , it can be done in O(n) time get an array.

One-dimensional difference - template question AcWing 797. Difference
Add c to each number in the interval [l, r]: b[l] += c, b[r + 1] -= c
example question
AcWing797. Difference
input one A sequence of integers of length n. Next, enter m operations, each operation contains three integers l, r, c, which means adding c to each number between [l, r] in the sequence.
Please output the sequence after all operations are performed.

Input format
The first line contains two integers n and m.
The second line contains n integers, representing a sequence of integers.
Next m lines, each line contains three integers l, r, c, representing an operation.

Output format
A total of one line, containing n integers, representing the final sequence.

Data range
1≤n, m≤100000,
1≤l≤r≤n,
−1000≤c≤1000,
−1000≤value of elements in integer sequence≤1000
Input example:
6 3
1 2 2 1 2 1
1 3 1
3 5 1
1 6 1
Output example:
3 4 5 3 4 2

#include<bits/stdc+.和>
using namespace std;
const int N=1e5+10;
int a[N],b[N]; 
int main()
{
    
     
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) 
    {
    
    
        scanf("%d",&a[i]);
        b[i]=a[i]-a[i-1];      //构建差分数组
    }
    int l,r,c;
    while(m--)
    {
    
    
        scanf("%d%d%d",&l,&r,&c);
        b[l]+=c;     //将序列中[l, r]之间的每个数都加上c
        b[r+1]-=c;
    }
    for(int i=1;i<=n;i++) 
    {
    
    
        a[i]=b[i]+a[i-1];    //前缀和运算
        printf("%d ",a[i]);
    }
    return 0;
}

2D difference

Author: z Lin Shen Shi Jianlu
If it is extended to two dimensions, we need to add c to the value of each element in the selected sub-matrix of the two-dimensional array, whether it can also achieve O(1) time complexity. The answer is yes, consider two-dimensional difference.

The a[][] array is the prefix and array of the b[][] array, then b[][] is the difference array of a[][] The original array: a[i][j] Let's construct the difference array
:
b [i][j]
makes a[i][j] in the a array is the sum of the rectangular elements enclosed by the upper left corner (1,1) to the lower right corner (i,j) of the b array.

How to construct the b array?

Let's think backwards.

The purpose of constructing a two-dimensional difference array is to make the operation of adding c to each element in the selected neutron matrix in the original two-dimensional array a, which can be optimized from the time complexity of O(n*n) to O (1)

It is known that the selected sub-matrix in the original array a is a rectangular area surrounded by (x1, y1) as the upper left corner and (x2, y2) as the lower right corner;

Always remember that array a is the prefix and array of array b. For example, the modification of b[i][j] of array b will affect every number in array a from a[i][j] and beyond. .

Assuming that we have already constructed the b array, analogous to the one-dimensional difference, we perform the following operations
to add the value of each element in the selected sub-matrix to the time complexity o(1)

b[x1][y1] + = c;

b[x1,][y2+1] - = c;

b[x2+1][y1] - = c;

b[x2+1][y2+1] + = c;

Each time the above operation is performed on the b array, it is equivalent to: time complexity o(n2)

for(int i=x1;i<=x2;i++)
  for(int j=y1;j<=y2;j++)
       a[i][j]+=c;

Let's draw a picture to understand this process:
insert image description here
b[x1][ y1 ] +=c ; Corresponding to Figure 1, add c to the elements of the blue rectangle area in the entire array a.
b[x1,][y2+1]-=c ; Corresponding to Figure 2, subtract c from the elements of the green rectangle area in the entire array a, so that the elements in it will not change.
b[x2+1][y1]- =c ; Corresponding to Figure 3, subtract c from the elements of the purple rectangle area in the entire array a, so that the elements in it will not change.
b[x2+1][y2+1]+=c; Corresponding to Figure 4, add c to the elements of the red rectangle area in the entire array a, the red ones are equivalent to being subtracted twice, plus c once , to restore it.
insert image description here

We encapsulate the above operations into an insert function:

void insert(int x1,int y1,int x2,int y2,int c)
{
    
         //对b数组执行插入操作,等价于对a数组中的(x1,y1)到(x2,y2)之间的元素都加上了c
    b[x1][y1]+=c;
    b[x2+1][y1]-=c;
    b[x1][y2+1]-=c;
    b[x2+1][y2+1]+=c;
}

We can first assume that the a array is empty, then the b array is also empty at first, but in fact the a array is not empty, so we let (i, j) be the upper left corner to (i, j) every time The elements in the area of ​​the upper right corner (actually, the area of ​​a small square) are inserted into c=a[i][j], which is equivalent to adding in the range from (i,j) to (i,j) in the original array a a[i][j] , so n*m insertion operations are performed, and the differential b array is successfully constructed.

This is called curve saving the country.

code show as below:

  for(int i=1;i<=n;i++)
  {
    
    
      for(int j=1;j<=m;j++)
      {
    
    
          insert(i,j,i,j,a[i][j]);    //构建差分数组
      }
  }

Two-dimensional difference - template question AcWing 798. Difference matrix
Add c to all elements in the sub-matrix with (x1, y1) as the upper left corner and (x2, y2) as the lower right corner:
S[x1, y1] += c, S[x2 + 1, y1] -= c, S[x1, y2 + 1] -= c, S[x2 + 1, y2 + 1] += c

Example question
AcWing 798. Difference matrix
Input an integer matrix with n rows and m columns, and then input q operations, each operation contains five integers x1, y1, x2, y2, c, where (x1, y1) and (x2, y2 ) represent the upper-left and lower-right coordinates of a submatrix.
Each operation adds c to the value of each element in the selected submatrix.
Please output the matrix after all operations.

Input Format
The first line contains integers n,m,q.

The next n lines, each containing m integers, represent a matrix of integers.

The next q lines, each line contains 5 integers x1, y1, x2, y2, c, representing an operation.

The output format
has n lines in total, and each line contains m integers, indicating the final matrix after all operations are completed.

Data range
1≤n, m≤1000,
1≤q≤100000,
1≤x1≤x2≤n,
1≤y1≤y2≤m,
−1000≤c≤1000, −1000≤value
of elements in the matrix≤1000 input
Example:
3 4 3
1 2 2 1 3 2
2 1
1 1 1
1
1 1 2 2 1 1 3 2 3 2 3
1 3 4 1
Output example:
2 3 4 1
4 3 4 1
2 2 2 2

#include<iostream>
#include<cstdio>
using namespace std;
const int N = 1e3 + 10;
int a[N][N], b[N][N];
void insert(int x1, int y1, int x2, int y2, int c)
{
    
    
    b[x1][y1] += c;
    b[x2 + 1][y1] -= c;
    b[x1][y2 + 1] -= c;
    b[x2 + 1][y2 + 1] += c;
}
int main()
{
    
    
    int n, m, q;
    cin >> n >> m >> q;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            cin >> a[i][j];
    for (int i = 1; i <= n; i++)
    {
    
    
        for (int j = 1; j <= m; j++)
        {
    
    
            insert(i, j, i, j, a[i][j]);      //构建差分数组
        }
    }
    while (q--)
    {
    
    
        int x1, y1, x2, y2, c;
        cin >> x1 >> y1 >> x2 >> y2 >> c;
        insert(x1, y1, x2, y2, c);
    }
    for (int i = 1; i <= n; i++)
    {
    
    
        for (int j = 1; j <= m; j++)
        {
    
    
            b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1];  //二维前缀和
        }
    }
    for (int i = 1; i <= n; i++)
    {
    
    
        for (int j = 1; j <= m; j++)
        {
    
    
            printf("%d ", b[i][j]);
        }
        printf("\n");
    }
    return 0;
}

3D difference

Observe one-dimensional

b[l] = s[l] - s[l-1]  

+s[l] , -s[l-1]
two-dimensional

b[i][j] = s[i][j] - s[i-1][j] - s[i][j-1] + s[i-1][j-1]

-s[i-1][j] , -s[i][j-1] , +s[i][j] , +s[i-1][j-1] have an odd number of minus one is
negative , an even number minus one is positive
0 0 { s[ i - 0 ][ j - 0 ] = s[ i ][ j ] } +1
0 1 { s[ i - 0 ][ j - 1 ] = s[ i ] [ j - 1] } -1
1 0 { s[ i - 1 ][ j - 0 ] = s[ i - 1 ][ j ] } -1 1 1
{ s[ i - 1][ j - 1 ]} -1
If you add c to the original sequence between (x1, y1) and (x2, y2):

b[x1][y1] += c;  //00
b[x1][y2+1] -= c; //01
b[x2+1][y1] -= c; //10
b[x2+1][y2+1] += c; //11

In the same way,
three-dimensional

b[i][j][k] = s[i][j][k] - s[i-1][j][k] - s[i][j-1][k] + s[i-1][j-1][k]- s[i][j][k-1] + s[i-1][j][k-1] + s[i][j-1][k-1] - s[i-1][j-1][k-1];

Add c to the original sequence between (x1, y1, z1) and (x2, y2, z2):

b[x1    ][y1    ][z1    ]   += c;  // 000
b[x1    ][y1    ][z2 + 1]   -= c;  // 001
b[x1    ][y2 + 1][z1    ]   -= c;  // 010
b[x1    ][y2 + 1][z2 + 1]   += c;  // 011
b[x2 + 1][y1    ][z1    ]   -= c;  // 100
b[x2 + 1][y1    ][z2 + 1]   += c;  // 101
b[x2 + 1][y2 + 1][z1    ]   += c;  // 110
b[x2 + 1][y2 + 1][z2 + 1]   -= c;  // 111

Example question
AcWing 1232. Three-body attack
Three-body people will attack the earth.
In order to resist the attack, the earthlings sent out A×B×C warships, which lined up a cube with layer A, row B, and column C in space.
Among them, the life value of the battleship (denoted as battleship (i,j,k)) in row j, column k of layer i is d(i,j,k).
Trisolarans will launch m rounds of "cube attacks" on the earth, and each attack will cause the same damage to all warships in a small cube.
Specifically, the t-th round of attack is described by 7 parameters lat, rat, lbt, rbt, lct, rct, ht
; ]'s battleship (i,j,k) will be damaged by ht.
If the cumulative total damage received by a battleship exceeds its defense power, the battleship will explode.
The Earth Commander wants you to tell him which round the first battleship exploded after.

Input format
The first line includes 4 positive integers A, B, C, m;

The second line contains A×B×C integers, where the ((i−1)×B+(j−1))×C+(k−1)+1 number is d(i, j, k)
; 3 to line m+2, line (t − 2) contains 7 positive integers lat, rat, lbt, rbt, lct, rct, ht.

Output Format
Output which round of attack the first exploded warship exploded after.
It is guaranteed that such a battleship must exist.

Data range
1≤A×B×C≤106,
1≤m≤106,
0≤d(i, j, k), ht≤109,
1≤lat≤rat≤A,
1≤lbt≤rbt≤B,
1 ≤lct≤rct≤C
Layers, rows, and columns all start from 1.

Input example:
2 2 2 3
1 1 1 1 1 1 1
1 1
2 1 2 1 1 1 1 1 1 2 1 2 1 1
1 1 1 1 1 2
Output example:
2
examples explain
the attack in the second round After that, the battleship (1,1,1) suffered a total of 2 points of damage, which exceeded its defense and caused an explosion.

Note that A×B×C<=1e6, opening a three-dimensional array may time out, and converting the corresponding three-dimensional coordinates into one-dimensional coordinates (i×B+j)×k is too many queries, and the binary solution is to find the first bombed one
. battleship

code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int const N=2e6+10;//多出一个面 (i,j,k,+1);
int a,b,c,m;
ll s[N];//原数组;
ll bb[N],dp[N]; //差分数组;
 int op[N/2][7];
int d[8][4]=
{
    
    
    {
    
    0,0,0,1},{
    
    0,0,1,-1},{
    
    0,1,0,-1},{
    
    0,1,1,1},
    {
    
    1,0,0,-1},{
    
    1,0,1,1},{
    
    1,1,0,1},{
    
    1,1,1,-1},
};
int get(int i,int j,int k)  //以一维数组的形式
{
    
    
    return (i*b+j)*c+k;
}
bool check(int mid)//判断是否是第一个被炸毁的;
{
    
    
    memcpy(bb,dp,sizeof bb);//拷贝;
    for(int i=1; i<=mid; i++)
    {
    
    
        //将位于(x1, y1, z1)和(x2, y2, z2)之间的原序列都减去h:
        int x1 = op[i][0], x2 = op[i][1];
        int y1 = op[i][2], y2 = op[i][3];
        int z1 = op[i][4], z2 = op[i][5], h = op[i][6];
        bb[get(x1,     y1,     z1)]     -= h;
        bb[get(x1,     y1,     z2 + 1)] += h;
        bb[get(x1,     y2 + 1, z1)]     += h;
        bb[get(x1,     y2 + 1, z2 + 1)] -= h;
        bb[get(x2 + 1, y1,     z1)]     += h;
        bb[get(x2 + 1, y1,     z2 + 1)] -= h;
        bb[get(x2 + 1, y2 + 1, z1)]     -= h;
        bb[get(x2 + 1, y2 + 1, z2 + 1)] += h;
    }
    memset(s,0,sizeof s);  //前缀和求更改后原数组;
    for(int i=1; i<=a; i++)
        for(int j=1; j<=b; j++)
            for(int k=1; k<=c; k++)
            {
    
    
                s[get(i,j,k)]=bb[get(i,j,k)];
                for(int u=1; u<8; u++)
                {
    
    
                    int x=i-d[u][0],y=j-d[u][1];
                    int z=k-d[u][2],t=d[u][3];
                    s[get(i,j,k)]-=s[get(x,y,z)]*t;
                }
                if(s[get(i,j,k)]<0)
                    return true;
            }
    return false;

}
int main()
{
    
    
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);

    cin>>a>>b>>c>>m;

    for(int i=1; i<=a; i++)
        for(int j=1; j<=b; j++)
            for(int k=1; k<=c; k++)
                cin>>s[get(i,j,k)];

    //差分
    for(int i=1; i<=a; i++)
        for(int j=1; j<=b; j++)
            for(int k=1; k<=c; k++)
                for(int u=0; u<8; u++) //一共8种情况;000 001 010...
                {
    
    
                    int x=i-d[u][0],y=j-d[u][1],z=k-d[u][2],t=d[u][3];
                    dp[get(i,j,k)]+=s[get(x,y,z)]*t;
                }

    //输入m个操作;
    for(int i=1; i<=m; i++)
        for(int j=0; j<7; j++)
            cin>>op[i][j];

    //二分查找
    int l=1,r=m;
    while(l<r)
    {
    
    
        int mid=l+r >> 1;
        if(check(mid)) //如果第mid操作有炸毁,往前找
            r=mid;
        else
            l=mid+1;
    }

    cout<<r<<endl;

    return 0;
}

Guess you like

Origin blog.csdn.net/weixin_52879528/article/details/123227266