LOJ 一本通提高篇4.1樹狀數組 例題+練習

複習時食用,會比較簡略。

原理不講,還不會的先下車。


目錄

#130. 樹狀數組 1 :單點修改,區間查詢—>板子不講。

#10114. 「一本通 4.1 例 2」數星星 Stars

#10115. 「一本通 4.1 例 3」校門外的樹

#10116. 「一本通 4.1 練習 1」清點人數—>板子不講。

#10117. 「一本通 4.1 練習 2」簡單題

#133. 二維樹狀數組 1:單點修改,區間查詢


#10114. 「一本通 4.1 例 2」數星星 Stars

題目

題目大意

給定n個點。

定義每個點的等級是在該點左下方(含正左、正下)的點的數目。

試統計每個等級有多少個點。

座標用兩個整數x,y表示,不會有星星重疊。

星星按y座標增序給出, 座標相同的按x座標增序給出。

對於全部數據,1<=N<=1.5*10^4,0<=x,y<=3.2*10^4。

題目分析

我都加粗了的東西你一定要看!這道題好像跟板子沒什麼區別。

因爲已經按y座標增序給出了,所以可以一邊輸入一邊做。

(在ta前面輸入的在ta的下面,在ta後面輸入的y座標比ta大所以對ta沒什麼影響)

然後就看小於等於ta的x座標(即在ta的左邊或下面)就好啦。

噢還有一個big keng:lowbit(0)=0!!!麻煩手動右移一位。

以上。

代碼

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int n,tr[64010],ans[15010];
int lowbit(int x) { return x&-x; }

void add(int x)
{
	while(x<=32001)
	{
		tr[x]++;
		x+=lowbit(x);
	}
}

int sum(int x)
{
	int s=0;
	while(x!=0)
	{
		s+=tr[x];
		x-=lowbit(x);
	}
	return s;
}

int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		int x,y; scanf("%d%d",&x,&y);
		x++; add(x); ans[sum(x)-1]++;//不包括ta自己 
		//lowbit(0)=0樹狀數組的座標裏沒0
		//所以都向右移一位ba 
	}
	for(int i=0;i<=n-1;i++) printf("%d\n",ans[i]);
	return 0;
}

 

#10115. 「一本通 4.1 例 3」校門外的樹

題目

題目大意

有兩種操作:

k=1,讀入l,r表示在l到r之間種上一種樹,每次操作種的樹的種類都不同;

k=2,讀入l,r表示詢問l到r之間有多少種樹。

對於20%的數據,1<=n,m<=100;

對於60%的數據,1<=n<=10^3,1<=m<=5*10^4;

對於100%的數據,1<=n,m<=5*10^4,保證l,r>0。

題目分析

核心(敲黑板!!!):answer=一共有的樹的種類-前面有我沒有的種類-後面有我沒有的種類。 

沒了?沒了。

代碼

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int n,m,jia=0;//jia即爲一共有的樹的種類
int trl[100010],trr[100010];
int lowbit(int x) { return x&-x; }

void add(int x,int a[])
{
	while(x<=n)
	{
		a[x]++;
		x+=lowbit(x);
	}
}

int sum(int x,int a[])
{
	int s=0;
	while(x)
	{
		s+=a[x];
		x-=lowbit(x);
	}
	return s;
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int k,x,y; scanf("%d%d%d",&k,&x,&y);
		if(k==1) jia++,add(n-x+1,trl),add(y,trr);
		else printf("%d\n",jia-sum(x-1,trr)-sum(n-y,trl));
		//核心核心!answer=樹的種類-前面有我沒有的-後面有我沒有的 
		//畫圖畫圖!!! 
	}
	return 0;
}

 

#10117. 「一本通 4.1 練習 2」簡單題

 

#133. 二維樹狀數組 1:單點修改,區間查詢

題目

題目大意

給出一個n*m的零矩陣,要完成如下操作:

 

對於10%的數據,n=1;

對於另10%的數據,m=1;

對於全部數據,1<=n,m<=2^12,1<=x,a,c<=n,1<=y,b,d<=m,|k|<=10^5。

保證操作數目不超過3*10^5,且詢問的子矩陣存在。 

  • 1 x y k:表示元素Ax,y自增k;
  • 2 a b c d:表示詢問左上角爲(a,b),右下角爲(c,d)的子矩陣內所有數的和。

題目分析

求矩陣:sum(x2, y2)-sum(x2,y1-1)-sum(x1-1,y2)+sum(x1-1,y1-1)

這個不用說了都知道吧。不懂???畫圖去。

顯然這是個二維樹狀數組。

你讓我講我也不會講(來自蒟蒻的理直氣壯)。

好吧。要看大橘,目光要長遠。你需要把ta抽絲剝繭?讓ta現出本質。

All in all:每一行是一個樹狀數組,每一列是一個樹狀數組。(仔細琢磨啊!!)

看完的把你畫的圖90度轉看哈。

就這樣。

代碼

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int n,m;
long long tr[8200][8200];
int lowbit(int x) { return x&-x; }

void add(int x,int y,int k)
{
	while(x<=n)
	{
		int yy=y;
		while(yy<=m)//一維變二維! 
		{
			tr[x][yy]+=k;
			yy+=lowbit(yy);
		}
		x+=lowbit(x);
	}
}

long long sum(int x,int y)
{
	long long s=0;
	while(x!=0)
	{
		int yy=y;
		while(yy!=0)
		{
			s+=tr[x][yy];
			yy-=lowbit(yy);
		}
		x-=lowbit(x);
	}
	return s;
}

int main()
{
	scanf("%d%d",&n,&m); int t;
	while(scanf("%d",&t)!=EOF)
	{
		if(t==1)
		{
			int x,y,k;
			scanf("%d%d%d",&x,&y,&k);
			add(x,y,k);
		}
		else
		{
			int a,b,c,d; scanf("%d%d%d%d",&a,&b,&c,&d);
			long long aa,bb=0,cc=0,dd=0;
			aa=sum(c,d);
			if(b-1) bb=sum(c,b-1);
			if(a-1) cc=sum(a-1,d);
			if((a-1)&&(b-1)) dd=sum(a-1,b-1);
			printf("%lld\n",aa-bb-cc+dd);
			//求矩陣
		}
	}
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章