主頁 > 後端開發 > 樹狀陣列筆記整理

樹狀陣列筆記整理

2023-01-20 06:57:46 後端開發

樹狀陣列介紹

樹狀陣列,顧名思義,就是樹狀的一維陣列,

二叉樹同樣也可以用一維陣列存盤,我們以二叉樹進行類比,

image

如圖所示,圖中節點的序號就是存在陣列中的下標

記父節點序號\(p\),子節點序號\(s\)

則有:

\(p\) \(=\) \(s\) \(/\) \(2\) (向下取整),

左子節點 \(s_{left}\) \(=\) \(p\) \(* 2\)

右子節點 \(s_{right}\) \(=\) \(p\) \(*2+1\)

綜上可知,二叉樹能用一維陣列存,是由于其父子節點間存在一定關系,以至于不需要用額外的變數來表示資訊,

那類比到樹狀陣列中,可以發現:

image

\(c\)陣列即為樹狀陣列,\(c_i\) 表示區間\(a\)\([i-lowbit(i),i]\) 的和,

ps:點我了解lowbit運算是什么

同樣記父節點下標為 \(p\) ,子節點下標為 \(s\)

則有:

\(p\) \(=\) \(s\) \(+\) \(lowbit(s)\)

由這條公式亦可反推出:

\(s\) \(=\) \(p\) \(-\) \(2^i\)(\(0 \le i < p_{last}\))

這里的 \(p_{last}\) 指的是 \(p\) 二進制表示下最后一位 \(1\) 所在的位數,

例如:\(6\) 的二進制數表示為 \(110\),則它的 \(p_{last}\)\(1\),(這里的位數從右往左\(0\)開始記),

因為公式 \(1\)\(s\) 加上自身 \(lowbit(s)\) 得到 \(p\) 其程序一定會產生進位,且 \(lowbit(s)\) 一定小于 \(lowbit(p)\) ,所以可以倒推得到子節點,

由于以上關系,樹狀陣列不僅可以用一維陣列存,而且還衍生出了一系列用途,

樹狀陣列功能

單點增加

Q:給序列中的一個數 \(a[x]\) 加上 \(y\) ,此時如何維護樹狀陣列?

A:將所有包含 \(a[x]\) 的節點加上 \(y\) 即可,也就是 \(c[x]\) 和它所有的祖先節點,

ps:初始化時亦可運用此操作,

點擊查看代碼
void add(int x,int y){
	for (; x <= N;x += x&-x)  c[x] += y;
	return ;
}

動態維護前綴和

之所以說動態維護,因為用樹狀陣列維護前綴和只需要 \(\log N\) 的時間復雜度,更為優秀,

Q:求 \(a\) 陣列 \(a_i \sim a_x\) 的和,

A:將數 \(x\) 分成若干個區間,

區間共同特點:若區間結尾為 \(R\),則區間長度就等于 \(lowbit(R)\),即 \(R\) 二進制分解下最小的整數次冪,

舉例:當 \(x\) = \(7\)

image

如圖所示,

區間劃分方式與樹狀陣列相同,前面又提到“\(c\)陣列即為樹狀陣列,\(c_i\) 表示區間\(a\)\([i-lowbit(i),i]\) 的和,”

因此只需要將這幾個區間所對應的 \(c_i\) 相加,即可得到前綴和,

點擊查看代碼
int ask(int x){
	int ans = 0;
	for (; x ; x -= x & -x) ans += c[x];
	return ans;
}

例題【具體應用】

主要利用樹狀陣列可以快速求前綴和的優勢,以資料范圍為下標,快速統計區間內的個數(或所需要的資訊),適用于資料范圍適中(一般為 \(0 \le x \le 10^6\))且需要多次求前綴和的題目,

【例題1】 三元上升子序列

【題目分析】

對于一個數 \(x\) ,計算其作為 \(j\) 時,位置在它前面比它小的數 \(x_{min}\)、位置在它后面比它大的數 \(x_{max}\),運用乘法原理的知識可知,將\(x_{min} \times x_{max}\),即可得到 \(x\) 作為 \(j\) 時的方案數 ,列舉所有 \(x\) ,即可得到總方案數,

【樹狀陣列作用】

統計 \(x_{min}\)\(x_{max}\) 時,即可將數 \(x\) 的范圍作為樹狀陣列的下標,

此時兩種操作所代表的意思分別為:

\(add(x,1)\) 表示數值為 \(x\) 的數的個數 \(+1\)

\(sum(y)\) 表示在已經掃描過的區間內,數值為從 \(1 \sim y\) 的所有數的個數,

順序掃描序列,對于數 \(x\) ,統計兩個資訊,

\(r_{i,0}\) 表示位置在數 \(x\) 前面,且比它小的數,

\(r_{i,1}\) 表示位置在數 \(x\) 前面,且比它大的數,

位置在數 \(x\) 后面,且比數 \(x\) 大的數就等于:

\(所有數 - 所有位置在 x 前面比 x 小的數 - r{i,1}\)

【code】

點擊查看代碼
#include<iostream>
#include<cstdio>
#include<cmath>
#define ll long long
using namespace std;
ll tree[100005],n,num;
ll r[40005][2],a[100005];
void add(ll x,ll y){
	for(;x<=100005;x+=(x&-x)) tree[x]+=y;
}
ll sum(ll x){
	ll ans=0;
	for(;x;x-=(x&-x)) ans+=tree[x];
	return ans;
}
int main(){
	scanf("%lld",&n);
	for(int i=1;i<=n;i++){
		ll x;
		scanf("%lld",&x);
		a[i]=x;
		num=max(num,x);
		add(x,1);
		r[i][0]=sum(x-1);
		r[i][1]=sum(num)-sum(x);
	}
	ll ans=0;
	for(int i=1;i<=n;i++)
		ans+=r[i][0]*(sum(num)-sum(a[i])-r[i][1]);
	cout<<ans<<endl;
	return 0;
}

【summary】

此題算是初步認識了以數值范圍為下標的樹狀陣列的用法,下一大點求逆序對的思想與此相同,

【例題2】 [USACO04OPEN] MooFest G 加強版

【題目分析】

將奶牛按照音量從小到大進行排序,保證當前奶牛的音量一定最大,然后分類討論所有比當前奶牛音量小的奶牛與當前奶牛的距離(坐標比當前奶牛大的和坐標比當前奶牛小的),兩者相加,乘上當前奶牛音量,列舉每個奶牛,即可得到答案,

【樹狀陣列作用】

定義兩個樹狀陣列,都是以距離的范圍作為下標, \(c\) 陣列用于統計對應距離的個數,\(t\) 陣列用于表示對應距離 \(\times\) 對應 距離個數的總數,通過二者,即可快速計算距離差,

【code】

計算程序的解釋已在代碼中注釋出來,

點擊查看代碼
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
ll n,t[50005],c[50005];
struct A{
	ll v,x;
}a[50005];
bool cmp(A xx,A yy){
	if(xx.v==yy.v) return xx.x<yy.x;
	return xx.v<yy.v; 
}
void addc(ll x,ll y){
	for(;x<=50000;x+=(x&-x)) c[x]+=y;
}
void addt(ll x,ll y){
	for(;x<=50000;x+=(x&-x)) t[x]+=y;
}
ll sumc(ll x){
	ll sum=0;
	for(;x;x-=(x&-x)) sum+=c[x];
	return sum;
}
ll sumt(ll x){
	ll sum=0;
	for(;x;x-=(x&-x)) sum+=t[x];
	return sum;
}
int main(){
	scanf("%lld",&n);
	for(int i=1;i<=n;i++) scanf("%lld%lld",&a[i].v,&a[i].x);
	sort(a+1,a+n+1,cmp); 
	ll ans=0,max_num=0;
	for(int i=1;i<=n;i++){
		max_num=max(max_num,a[i].x);
		//以下距離之間的比較限于所有音量比當前奶牛小的奶牛,
		//a[i].x*sumc(a[i].x-1) 表示當前奶牛的距離*距離比當前奶牛小的奶牛個數,
		//sumt(a[i].x-1) 表示所有距離比當前奶牛小的奶牛的距離和,
		//sumt(max_num)-sumt(a[i].x) 表示所有距離比當前奶牛大的奶牛的距離之和,
		//sumc(max_num)-sumc(a[i].x))*a[i].x 表示當前奶牛距離 * 距離比當前奶牛大的奶牛個數
		ans+=a[i].v*(a[i].x*sumc(a[i].x-1)-sumt(a[i].x-1)+(sumt(max_num)-sumt(a[i].x))-(sumc(max_num)-sumc(a[i].x))*a[i].x) ;
		addc(a[i].x,1);
		addt(a[i].x,a[i].x);
	}
	cout<<ans<<endl;
	return 0;
}

【summary】

這一題的重點給到題目中樹狀陣列 \(t\),主要識訓為:以數值范圍為下標的樹狀陣列,能夠處理的資訊不僅限于個數,

【例題3】P1972 [SDOI2009] HH的項鏈

【題意分析】

本題核心:如何判斷一個區間內的貝殼是否重復?

當右端點 \(r\) 固定時,不論 \(l\) 取何值,對于任意一組重復的貝殼,都可以只統計最右端的貝殼,

原因:設一組重復貝殼中最右端的貝殼所在的位置為 \(pos_r\),那么當 \(pos_r < l\) 時,其他貝殼也不可能算進統計中,當 $pos_r \ge l $時,無論其他貝殼是否被包括,對于區間的貢獻都只有 \(1\),因此,只計算最右端的貝殼即可,

因此,只需要將所有詢問區間按 \(r\) 從小到大排序,計算答案即可,

【樹狀陣列作用】

以位置為下標,每遇到一個新的數 \(num(num \le r)\),判斷它是否重復,如果重復,那么將上一個相同的數的貢獻值 \(-1\),將當前數的貢獻值 \(+1\)

對于一段區間 \([l,r]\),答案為 \(sum(r)-sum(l-1)\)

【code】

點擊查看代碼
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int n,m,ask_r,prev,pos;
int vis[1000005],a[1000005],t[1000005],ans[1000005];
struct A{
	int l,r,num;
}ask[1000005];
bool cmp(A x,A y){
	return x.r<y.r;
}
int find(int pos){
	ask_r=ask[pos++].r;
	while(ask_r==ask[pos].r) pos++;
	return pos-1;
}
void add(int x,int y){
	for(;x<=n;x+=(x&-x)) t[x]+=y;
	return;
} 
int sum(int x){
	int su=0;
	for(;x;x-=(x&-x)) su+=t[x];
	return su;
}
void replace(){
	for(int i=ask[prev].r+1;i<=ask_r;i++){
		if(vis[a[i]]!=0) add(vis[a[i]],-1);
		add(i,1);
		vis[a[i]]=i;
	}
	for(int i=prev+1;i<=pos;i++) ans[ask[i].num]=sum(ask[i].r)-sum(ask[i].l-1);
	return;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	scanf("%d",&m);
	for(int i=1;i<=m;i++) scanf("%d%d",&ask[i].l,&ask[i].r),ask[i].num=i;
	sort(ask+1,ask+m+1,cmp);
	while(1){
		if(pos==m) break;
		prev=pos;
		pos=find(pos+1);
		replace();
	}
	for(int i=1;i<=m;i++) cout<<ans[i]<<endl;
	return 0;
}

\(summary\)

此題不再以資料范圍為下標,而是以位置為下標,對于樹狀陣列的應用更加靈活,在想到以最右端的貝殼為有價值的貢獻時,對應到樹狀陣列的操作就可以是上一個重復的數的貢獻值 \(-1\),當前數的貢獻值 \(+1\),然后用前綴和統計區間內的個數,算進一步的開闊思維,

求逆序對

本質上也是通過樹狀陣列單點增加和區間求和的操作進行計算,作為一個專題單獨列出來,

桶排+樹狀陣列:

1.桶排部分:

對于一個序列 \(a\) , 我們建立一個 \(cnt\) 陣列,\(cnt[x]\) 表示 \(x\) 在序列 \(a\) 中出現過的次數,當 \(a_i=val\) 時,\(cnt[val]++\)

2.樹狀陣列部分:

倒序掃描序列 \(a\),對于新加入的數 \(a_i\),查詢 \(cnt[1~a_i-1]\) 的前綴和,并將回傳的前綴和加入答案,前綴和部分就可以用樹狀陣列來維護,

操作簡單粗暴,但相當好用,

點擊查看代碼
for ( int i = n; i; i --) {
	ans += ask (a[i] - 1);
	add (a[i] , 1 );
}

【例題】

接下來通過兩道題進一步了解一下逆序對的考法,(不做一下真沒想到還能這樣考,)

【例題1】P2448 無盡的生命

【題意簡述】

看到題目顯而易見是求逆序對個數,

【思路分析】

看到資料范圍 \(x_i,y_i \le 2^{31}-1\)\(k \le 10^5\),資料值域大但是個數少,且與資料之間的大小關系有關,因此考慮離散化,

離散化簡單介紹

離散化實際就是一種映射,當資料值域過大而個數有限時,可以嘗試離散化,

具體程序以此題為例,假設給出這么一組資料

2

123456789 123456

987654321 123456

首先將所有出現過的數收集起來,存進 \(a\) 陣列,并進行排序,然后再去重保存進 \(pos\) 陣列當中,

接下來就可以建立映射關系,將數值大的數在 \(num\) 陣列中用數值小的數代替,但各個數之間的大小關系不變,接下來交換操作先用二分答案在 \(pos\) 陣列中檢索,然后通過映射在 \(num\) 陣列中進行交換,

最終被交換過的數之間的逆序對在 \(num\) 陣列中求即可,

被交換的數與未被交換的數之間的逆序對

考慮每個被交換的數對答案的貢獻,

\(x<y\),當 \(x\)\(y\) 交換后,

對于 \(x\) 來說, \(x \sim y\) 之間所有未被交換的數都比 \(x\) 大,形成逆序對,

對于 \(y\) 來說,\(x \sim y\) 之間所有未被交換的數都比 \(y\) 小,形成逆序對,

逆序對個數都為\(x \sim y\) 之間所有未被交換的數,

溫馨提示:以下主要為代碼實作講解,本質思想同上,

對于交換過后的 \(num\) 陣列,\(num_i\) 表示的是位置 \(pos_i\) 上當前所在的數在 \(num\) 陣列中對應的數,記數 \(x\) 為位置 \(pos_i\) 上當前所在的數,

\(pos_{num_i}\) 表示數 \(x\) 現在所在的位置,

\(pos_i\) 表示數 \(x\) 原來在的位置,

\(\left\vert pos_i-pos_{num_i}-1\right\vert\) 表示兩個位置間所有的數,

\(\left\vert num_i-i-1\right\vert\) 表示兩個位置間所有被交換過的數,

因此所有未被交換的數就為 \(\left\vert pos_i-pos_{num_i}-1\right\vert - \left\vert num_i-i-1\right\vert\)

【code】

點擊查看代碼
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
struct A{
	int x,y;
}a[100005];
int k,pos[200005],num[200005],cnt,len;
int t[100005];
void add(int x){
	for(;x<=len;x+=(x&-x)) t[x]+=1;
}
long long sum(int x){
	long long ans=0;
	for(;x;x-=(x&-x)) ans+=t[x];
	return ans;
}
int find(int x){
	int l=1,r=len;
	while(l<r){
		int mid=(l+r)>>1;
		if(pos[mid]<x) l=mid+1;
		else if(pos[mid]>x) r=mid-1;
		else return mid;
	}
} 
int main(){
	scanf("%d",&k);
	for(int i=1;i<=k;i++){
		scanf("%d%d",&a[i].x,&a[i].y);
		num[++cnt]=a[i].x;
		num[++cnt]=a[i].y;
	}
	sort(num+1,num+cnt+1);
	for(int i=1;i<=cnt;i++){
		if(num[i]==num[i-1]) continue;
		pos[++len]=num[i];
	}
	for(int i=1;i<=len;i++) num[i]=i;
	for(int i=1;i<=k;i++){
		int pos1=find(a[i].x);
		int pos2=find(a[i].y);
		swap(num[pos1],num[pos2]);
	}
	long long ans=0;
	for(int i=len;i>=1;i--){
		add(num[i]);
		ans+=sum(num[i]-1);
		ans+=abs(pos[num[i]]-pos[i]-1)-abs(num[i]-i-1); 
	} 
	cout<<ans<<endl;
	return 0;
}

【summary】

重點在于與未交換的數之間的求解,題目中序列的長度可以長到一個陣列都存不下,但卻可以用公式求呢,

【例題2】P3531 [POI2012]LIT-Letters

【題目描述】

該題的重點在于如何從題面描述轉到求 \(逆序對\),抓到重點:

  • 交換 \(a\) 中相鄰兩個字符,求最少的交換次數,

  • \(a,b\) 中只含大寫字母,且資料保證 \(a\) 可以變成 \(b\)

\(b\) 串中的字符進行順序編號(假設此時 \(b\) 中并沒有重復的字母),并對應到 \(a\) 串中,

例如:

3
ABC
BCA

\(BCA\) 進行順序編號,對應到 \(ABC\) 就是 \(312\)

當序列 \(a\) 中存在數 \(a , b\),滿足 $pos_a < pos_b $ , \(a > b\),也就是形成逆序對,

而對于我們的目標,將 \(a\) 串變成 \(b\) 串,需滿足任意數 \(a , b\),都有 \(pos_a < pos_b\) , \(a < b\)

顯然我們需要通過一定操作,令逆序對都消失,以達到目標,

由于題目中的交換為交換相鄰的數,因此只要 \(a\)\(b\) 不交換,它們之間的相對位置就不會變,也就不能達成目標,

綜上所述,最少的交換次數就是逆序對的個數,

當字母重復時,我們要如何讓編號對應到 \(a\) 呢?

顯然逆序對個數越少越好,因此對于相同的字母,按出現的順序進行順序編號,代碼中用單向鏈表實作,

【code】

點擊查看代碼
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#define ll long long
using namespace std;
int now[30],prev[30],nex[1000005];
char s[1000005],ss[1000005];
int a[1000005],t[1000005],lens;
void add(int x,int y){
	for(;x<=lens;x+=(x&-x)) t[x]+=y;
	return;
}
ll sum(int x){
	ll ans=0;
	for(;x;x-=(x&-x)) ans+=t[x];
	return ans;
}
int main(){
	scanf("%d",&lens);
	cin>>(s+1);
	cin>>(ss+1);
	for(int i=1;i<=lens;i++){
		int ch=s[i]-'A';
		if(now[ch]==0) now[ch]=i;
		nex[prev[ch]]=i;
		prev[ch]=i;
	}
	for(int i=1;i<=lens;i++){
		int ch=ss[i]-'A';
		a[now[ch]]=i;
		now[ch]=nex[now[ch]];
	}
	ll ans=0;
	for(int i=lens;i>=1;i--){
		add(a[i],1);
		ans+=sum(a[i]-1);
	}
	cout<<ans<<endl;
	return 0;
}

區間增加,單點查詢

【模板】樹狀陣列2

思路剖析

相信經過上面的頭腦風暴,再來看這題已經相當簡單了,

此時主要運用到差分的思想,差分是前綴和的逆運算,

當要在區間 \([x,y]\) 加上 \(k\) 時,我們進行以下操作:

\(add(x,k) , add(y+1,-k)\)

此時對于區間求前綴和對于 \(x \sim y\),它的前綴和都為 \(k\),而到 \(y+1\) ,又變成 \(0\),此時的前綴和正好是區間增加的數,且不會對其它數產生影響,

因此,當查詢第 \(x\) 個數時,只需要輸出:

\(a_x(第 x 個數原本的數值) + sum(x)(變化的值)\)

即可,

code

點擊查看代碼
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int a[500005],c[500005],n,m;
void add(int x,int k){
	for(;x<=n;x+=x&-x) c[x]+=k;
	return;
}
int q(int x){
	int sum=0;
	for(;x;x-=x&-x) sum+=c[x];
	return sum;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=m;i++){
		int type;
		scanf("%d",&type);
		if(type==1){
			int x,y,k;
			scanf("%d%d%d",&x,&y,&k);
			add(x,k);
			add(y+1,-k);
		}
		else{
			int x;
			scanf("%d",&x);
			cout<<a[x]+q(x)<<endl;
		}
	}
	return 0;
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/542271.html

標籤:其他

上一篇:【專案實戰】從零到一搭建Spring Boot整合Mybatis-plus

下一篇:dubbo實戰篇:dubbo超時設定

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more