1. 程式人生 > 其它 >vue 中使用 國際化(i18n)

vue 中使用 國際化(i18n)

1.引言

樹狀陣列是一種非常好用的東西,主要鍛鍊lowbit。

以前學完了之後做了一個簡單的整理,但遠遠不夠。

所以,我來做這篇部落格,希望對大家有幫助。

2.問題

P3374 【模板】樹狀陣列 1

題目描述

如題,已知一個數列,你需要進行下面兩種操作:

  • 將某一個數加上 \(x\)
  • 求出某區間每一個數的和

輸入格式

第一行包含兩個正整數 \(n,m\),分別表示該數列數字的個數和操作的總個數。

第二行包含 \(n\) 個用空格分隔的整數,其中第 \(i\) 個數字表示數列第 \(i\) 項的初始值。

接下來 \(m\) 行每行包含 \(3\) 個整數,表示一個操作,具體如下:

  • 1 x k 含義:將第 \(x\) 個數加上 \(k\)
  • 2 x y 含義:輸出區間 \([x,y]\) 內每個數的和

輸出格式

輸出包含若干行整數,即為所有操作 \(2\) 的結果。

看到這題我們可以使用暴力演算法,模擬所有操作,顯然會超時。

接下來,我們就需要請我們的主角上場——樹狀陣列。

3.樹狀陣列

一、定義

我們定義陣列\(C_i\)表示樹狀陣列,就拿8個數舉例(假設原陣列是\(A_i\)):

  • \(C_1=A_1\)
  • \(C_2=A_1+A_2\)
  • \(C_3=A_3\)
  • \(C_4=A_1+A_2+A_3+A_4\)
  • \(C_5=A_5\)
  • \(C_6=A_5+A_6\)
  • \(C_7=A_7\)
  • \(C_8=A_1+A_2+A_3+A_4+A_5+A_6+A_7+A_8\)

就像這張圖,呈現出了一個斜著的樹形結構,所以叫做樹狀陣列。

而這些有什麼規律呢?我們來看看二進位制。

\(1_{10}=1_2\)
\(2_{10}=10_2\)
\(3_{10}=11_2\)
\(4_{10}=100_2\)
\(5_{10}=101_2\)
\(6_{10}=110_2\)
\(7_{10}=111_2\)
\(8_{10}=1000_2\)

很快我們就會找到規律:我們設\(k\)\(i\)二進位制末尾0的個數,那麼\(C_i\)就是從自己開始算,往前總共加\(2^k\)位。

可是,計算機不可能像我們一樣化成二進位制,數0的個數,然後算答案呀!所以,我們找到了另一種方法:\(\text{lowbit(i)=i and -i}\)

我們可以用6試一下:-6(6的補碼)的二進位制是010,和6的二進位制110按位與,得到10,就是2。而我們發現\(C_6\)就是正好加了總計2位。所以,\(C\)陣列的值就很好得到:

for i 1→n:
    C[i]=0
    for j (i-lowbit(i)+1)→i:
        C[i]+=A[i]

以後虛擬碼中的lowbit(i)均表示\(i\ \text{and -}i\),看著更方便。

二、單點修改

比如說上面那張圖,如果我們要修改\(A_1\),讓他加10,都要變哪些地方?我們來看看。

首先,對應的\(C_1\)需要改變。

接著,含有\(A_1\)的還有\(C_2,C_4,C_8\)

讀者可以自行拿2,3,4,5,6,7試試,最終發現每次在\(x\)位置修改,那麼下一個要修改的點在\(x+\text{lowbit(x)}\)。所以,我們可以寫出虛擬碼:

add(x,k):            在x這裡+k
    while x<=n:        只要後面還有(最後一定會到一個超過n的錯誤位置)
        C[x]+=k        我們就把當前的C修改
        x+=lowbit(x)   去下一個位置

我們完成了第一個操作,接下來就要思考求和了。

三、區間查詢

我們發現,比如7減去\(\text{lowbit(7)}\)得到6,然後減去\(\text{lowbit(6)}\)得到4,然後得到0。而這幾個對應的\(C_i\)相加就包含了1到7所有\(A_i\)。所以,我們可以使用一個類似字首和的思想,計算出結果。

也就是說,我們一直用當前數減去\(\text{lowbit(它本身)}\),所有經過的C都加上,就能得到答案。

sum(x):
    ans=0
    while x>0:
        ans+=C[x]
        x-=lowbit(x)

這時,對於每一組詢問\([x,y]\)的結果都必然是\(\text{sum(x)-sum(y-1)}\).

4.程式碼

整理完所有虛擬碼,最後給出這道題答案,but please don't 抄!

#include<iostream》
using namespace std;
int n,m;
int c[500005】;//C陣列
int a[500005];//A陣列
int lbt(int x){//lowbit
	return x&(-x);//注意-x要加括號
}
void query(){//初始化
	for(int i=1;i<=n;i++){
		for(int j=i-lbt(i)+1;j<=i;j++) c[i]+=a[j];
	}
void add(int x,int k){//單點修改
	for(imt i=x;i<=n;i+=lbt(i)) c[i]+=k;
}
int sum(int x){//區間查詢
	int ans=0;
	for(int i=x;i;i-=lbt(i)) ans+=C[i];
	return ans;
}
int main(){
	int op,x,y;
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>a[i];
	query();
	for(int i=1;i<=m;i++){
		cin>>op>>x>>y;
		if(op==1) add(x,y);//修改
		else cout<<sum(y)-sum(x-1)<<endl;//查詢
	}
	return 3221225477;//本程式碼已設定防作弊,請勿抄襲
}

最後,求點贊!