# Binary Indexed Tree# 2D Range Query# Prefix Sum

d796 - 區域調查

🔗 前往 ZeroJudge 原題

題目描述

題目給定一個 N x N 的矩陣,並有 Q 個操作。操作分為兩種:

  1. 查詢:給定矩陣的一個子矩形 (x1, y1) 到 (x2, y2),求該子矩形中所有元素的總和。
  2. 更新:給定矩陣中的一個元素 (x1, y1),將其值修改為 V。

解題思路

這題可以使用二維 Binary Indexed Tree (BIT) 來解決。BIT 是一種高效的資料結構,可以用於進行區間查詢和單點更新。

首先,我們初始化一個 N x N 的 BIT 陣列,並將原始矩陣中的元素值加到 BIT 中。 對於查詢操作,我們可以使用 BIT 的特性,通過四次查詢計算出子矩形的總和。具體來說,我們計算 (x2, y2) 的前綴和,然後減去 (x1-1, y2)、(x2, y1-1) 和 (x1-1, y1-1) 的前綴和,即可得到子矩形的總和。 對於更新操作,我們只需要將新的值與原始值之間的差值加到 BIT 中即可。

複雜度分析

  • 時間複雜度: O(Q * log^2(N)),其中 Q 是操作的數量,N 是矩陣的大小。每次查詢和更新操作都需要 O(log^2(N)) 的時間。
  • 空間複雜度: O(N^2),用於儲存 BIT 陣列。

程式碼

#include <iostream>
using namespace std;
int n,q,is,x1,y1,x2,y2,va;
int a[251][251],BIT[251][251];
int lowerbit(int x){
	return x&(-x);
}
int update(int x,int y,int v){
	for(int i=x;i<=n;i+=lowerbit(i))
		for(int j=y;j<=n;j+=lowerbit(j))
			BIT[i][j]+=v;
}
int sum(int x,int y){
	int rt=0;
	for(int i=x;i>0;i-=lowerbit(i))
		for(int j=y;j>0;j-=lowerbit(j))
			rt+=BIT[i][j];
	return rt;
}
int main(){
	cin.tie(0); ios::sync_with_stdio(false);
	cin >> n >> q; 
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j){
			cin >> a[i][j];
			update(i,j,a[i][j]);
		}
	while(q--){
		cin >> is;
		if(is==1){
			cin >> x1 >> y1 >> x2 >> y2;
			int tmpx=max(x1,x2),tmpy=max(y1,y2);
			x1=min(x1,x2);
			y1=min(y1,y2);
			x2=tmpx;
			y2=tmpy;
			cout << sum(x2,y2) - sum(x1-1,y2) - sum(x2,y1-1) + sum(x1-1,y1-1)  << "\n";
		}
		else{
			cin >> x1 >> y1 >> va;
			update(x1,y1,va-a[x1][y1]);
			a[x1][y1]=va;
		} 
	}
}

Discussion