1. 程式人生 > 其它 >一維差分/二維差分/ 三維差分 (通俗易懂)

一維差分/二維差分/ 三維差分 (通俗易懂)

  一維差分:

  • 比較容易理解, 就是每一個單位元素和前面一個元素的差值,通過O(n) 時間複雜度 就可以把這個佇列裡面的值給弄出啦。
  • 用於解決很多次修改區間問題

  二維差分:

  • 同理可得,不過的單位元素的差值= val【I】[J] - val【I】[J-1] - VAL[I-1][J]+VAL[I-1][J-1] ;    建議自己簡單畫一個圖來進行理解
  • O(n) 推導的時候  就 單位元素的差值+= val【I】[J-1] +VAL[I-1][J]-VAL[I-1][J-1] ; 
  • 在進行 矩形區間修改的時候就這樣:(+2) 表示差分陣列的值+2;

        為什麼?

  • 考慮 3 個關鍵元素 :單位元素的差值+= val【I】[J-1] +VAL[I-1][J]-VAL[I-1][J-1] ;  就是這個等號右邊的3個元素
  • 選擇一個修改區間外的方塊, 看他的 3個關鍵元素有沒有在 修改區間內,
  • 如果在內,看他對上面這個等式的影響,然後 單位元素的差值 加上影響的相反數即可。

    三維差分:

  • 同理可得,單位元素的差值= val【I】[J] [z] - val【I】[J-1] [z] - VAL[I-1][J][z]+VAL[I-1][J-1] -val[i][j][Z-1]+VAL[I-1][J][Z-1]+VAL[[I][J-1][Z-1]-VAL[I-1][J-1][Z-1]; 
  • 求差分

    關鍵:  偶數個 1 的 符號一致, 奇數個1 符號和 前面的偶數符號相反。(通過 0,0,0的來確認符號)

const 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}
};

二進位制 8 , 前面是 代表xyz值,後面是加減的值的正負。
View Code

     區間修改: 和上面同理,不過1 變成 R+1, 

    for(ri i=1;i<=mid;i++)
    {
        b[get(p[i].la,p[i].lb,p[i].lc)]-=p[i].val;
        b[
get(p[i].la,p[i].lb,p[i].rc+1)]+=p[i].val; b[get(p[i].la,p[i].rb+1,p[i].lc)]+=p[i].val; b[get(p[i].la,p[i].rb+1,p[i].rc+1)]-=p[i].val; b[get(p[i].ra+1,p[i].lb,p[i].lc)]+=p[i].val; b[get(p[i].ra+1,p[i].rb+1,p[i].lc)]-=p[i].val; b[get(p[i].ra+1,p[i].lb,p[i].rc+1)]-=p[i].val; b[get(p[i].ra+1,p[i].rb+1,p[i].rc+1)]+=p[i].val; }
View Code

 

例題:

試題 歷屆真題 三體攻擊【第九屆】【省賽】【A組】
     
資源限制
記憶體限制:256.0MB   C/C++時間限制:1.0s   Java時間限制:3.0s   Python時間限制:5.0s
問題描述
  三體人將對地球發起攻擊。為了抵禦攻擊,地球人派出了 A × B × C 艘戰艦,在太空中排成一個 A 層 B 行 C 列的立方體。其中,第 i 層第 j 行第 k 列的戰艦(記為戰艦 (i, j, k))的生命值為 d(i, j, k)。

  三體人將會對地球發起 m 輪“立方體攻擊”,每次攻擊會對一個小立方體中的所有戰艦都造成相同的傷害。具體地,第 t 輪攻擊用 7 個引數 lat, rat, lbt, rbt, lct, rct, ht 描述;
  所有滿足 i ∈ [lat, rat],j ∈ [lbt, rbt],k ∈ [lct, rct] 的戰艦 (i, j, k) 會受到 ht 的傷害。如果一個戰艦累計受到的總傷害超過其防禦力,那麼這個戰艦會爆炸。

  地球指揮官希望你能告訴他,第一艘爆炸的戰艦是在哪一輪攻擊後爆炸的。
輸入格式
  從標準輸入讀入資料。

  第一行包括 4 個正整數 A, B, C, m;
  第二行包含 A × B × C 個整數,其中第 ((i − 1)×B + (j − 1)) × C + (k − 1)+1 個數為 d(i, j, k);
  第 3 到第 m + 2 行中,第 (t − 2) 行包含 7 個正整數 lat, rat, lbt, rbt, lct, rct, ht。
輸出格式
  輸出到標準輸出。

  輸出第一個爆炸的戰艦是在哪一輪攻擊後爆炸的。保證一定存在這樣的戰艦。
樣例輸入
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
樣例輸出
2
樣例說明
  在第 2 輪攻擊後,戰艦 (1,1,1) 總共受到了 2 點傷害,超出其防禦力導致爆炸。
資料約定
  對於 10% 的資料,B = C = 1;
  對於 20% 的資料,C = 1;
  對於 40% 的資料,A × B × C, m ≤ 10, 000;
  對於 70% 的資料,A, B, C ≤ 200;
  對於所有資料,A × B × C ≤ 10^6, m ≤ 10^6, 0 ≤ d(i, j, k), ht ≤ 10^9。


  資源約定:
  峰值記憶體消耗(含虛擬機器) < 256M
  CPU消耗 < 2000ms


  請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入...” 的多餘內容。

  注意:
  main函式需要返回0;
  只使用ANSI C/ANSI C++ 標準;
  不要呼叫依賴於編譯環境或作業系統的特殊函式。
  所有依賴的函式必須明確地在原始檔中 #include <xxx>
  不能通過工程設定而省略常用標頭檔案。

  提交程式時,注意選擇所期望的語言型別和編譯器型別。
三體攻擊【第九屆】【省賽】【A組】

沒有AC的程式碼,最後一個時間超時,qwq,全網找了很久每找到一個AC的,哎

思路,二分答案+差分

#include <bits/stdc++.h>
using namespace std;
#define ri register int
#define M 2000050


template <class G >  void read(G &x)
{
    x=0;int f=0;char ch=getchar();
    while(ch<'0'||ch>'9'){f|=ch=='-';ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    x=f?-x:x;
    return ;
}
int A,B,C,m;
int get(int a,int b,int c)
{
    return (a*B+b)*C+c;
}
int xf[M],b[M];
const 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 val[M];

struct dian{
    int la,ra,lb,rb,lc,rc,val;
}p[M];
int op[9];

void init()
{
        for(ri i=1;i<=A;i++)
        {
          for(ri j=1;j<=B;j++)
           {
            for(ri k=1;k<=C;k++)
            {
              b[get(i,j,k)]=xf[get(i,j,k)];
              val[get(i,j,k)]=0; //
            }
           }
        }
}
bool ck(int mid)
{
    init();
    for(ri i=1;i<=mid;i++)
    {
        b[get(p[i].la,p[i].lb,p[i].lc)]-=p[i].val;
        b[get(p[i].la,p[i].lb,p[i].rc+1)]+=p[i].val;
        b[get(p[i].la,p[i].rb+1,p[i].lc)]+=p[i].val;
        b[get(p[i].la,p[i].rb+1,p[i].rc+1)]-=p[i].val;
        b[get(p[i].ra+1,p[i].lb,p[i].lc)]+=p[i].val;
        b[get(p[i].ra+1,p[i].rb+1,p[i].lc)]-=p[i].val;
        b[get(p[i].ra+1,p[i].lb,p[i].rc+1)]-=p[i].val;
        b[get(p[i].ra+1,p[i].rb+1,p[i].rc+1)]+=p[i].val;
    }
    for(ri i=1;i<=A;i++)
    {
        for(ri j=1;j<=B;j++)
        {
            for(ri k=1;k<=C;k++)
            {
                int  tmp=0;
                for(ri cur=1;cur<=7;cur++) // zhu yi shu zhu d fan wei 
                {
                    int x=i+d[cur][0],y=j+d[cur][1],z=k+d[cur][2],h=d[cur][3];
                    tmp+=val[get(x,y,z)]*h;
                }
                val[get(i,j,k)]=b[get(i,j,k)]-tmp;
                if(val[get(i,j,k)]<0) 
                {
                    return 1;
                }
            }
        }
    }
    return 0;
    
    
}
int main(){
    
    read(A);read(B);read(C);read(m);
    for(ri i=1;i<=A;i++)
    {
        for(ri j=1;j<=B;j++)
        {
            for(ri k=1;k<=C;k++)
            {
                read(val[get(i,j,k)]);
            }
        }
    }
    
    for(ri i=1;i<=A;i++)
    {
        for(ri j=1;j<=B;j++)
        {
            for(ri k=1;k<=C;k++)
            {
                int  tmp=0;
                for(ri cur=0;cur<=7;cur++) // zhu yi shu zhu d fan wei 
                {
                    int x=i+d[cur][0],y=j+d[cur][1],z=k+d[cur][2],h=d[cur][3];
                    tmp+=val[get(x,y,z)]*h;
                }
               xf[get(i,j,k)]=tmp;
            }
        }
    }
    for(ri i=1;i<=m;i++)
    {
        read(op[1]);read(op[2]);read(op[3]);read(op[4]);read(op[5]);read(op[6]);read(op[7]);
        p[i].la=op[1];p[i].ra=op[2];p[i].lb=op[3];p[i].rb=op[4];p[i].lc=op[5];p[i].rc=op[6];p[i].val=op[7];
    }
    int l=1,r=m;
    
    while(l<r)
    {
        int mid=(l+r)>>1;
        if(ck(mid)) r=mid;
        else l=mid+1;
    }
    printf("%d",r);
    return 0;

}
View Code