概念與實現就(lande)不寫了,反正一大堆
(嚴格來說其實不是模版題,但由於實際編碼接近模版題,當作模版題來說)
天文學家經常要檢查星星的地圖,每個星星用平面上的乙個點來表示,每個星星都有座標。我們定義乙個星星的「級別」為給定的星星中不高於它並且不在它右邊的星星的數目。天文學家想知道每個星星的「級別」。
5*4
*1 2 3
* * *
例如上圖,5號星的「級別」是3(1,2,4這三個星星),2號星和4號星的「級別」為1。
給你乙個地圖,你的任務是算出每個星星的「級別」。
(這圖要橫著看)
輸入的第一行是星星的數目n(1<=n<=60000),接下來的n行描述星星的座標(每一行是用乙個空格隔開的兩個整數x,y,0<=x,y<=32000)。
星星的位置互不相同。星星的描述按照y值遞增的順序列出,y值相同的星星按照x值遞增的順序列出。
由於說到(星星的描述按照y值遞增的順序列出,y值相同的星星按照x值遞增的順序列出。),就可以得出結論:每輸入一次x,輸出x位置的字首和,再將x加入樹狀陣列(這裡的先後順序可以保證不將自己算進答案中),可以得到答案:
以4為例,因為在之前字首和已經計算了比4的y值小的答案(y值遞增),又因為之前字首和已經計算了比4的x值小的答案(y值相同,x值遞增),所以正看時getsum(x)是4的左邊、正下方與左下方的所有星星個數。
所以實現的是乙個最基礎的樹狀陣列:
操作:1.單點修改
2.查詢字首和
int add(int x)
int getsum(int x)
操作:
1.單點修改
2.查詢區間和
這個沒什麼好說的,就是輸出稍作變動:
printf("%d\n",sum(y)-sum(x-1));
這個很好理解:
一數列a[1]-a[5]:1 2 8 6 30
字首和b[1]-b[5]:1 3 11 17 47
如果要查詢3-5的區間和:
a[3]+a[4]+a[5]=a[1]+a[2]+a[3]+a[4]+a[5]-a[1]-a[2]
=b[5]-b[2](這個總看得懂)
=b[5]-b[3-1]
所以……沒有所以了吧
操作:1.區間修改
2.單點查詢
區間修改要用到差分思想:
add(x,k);
add(y+1,-k);
如果x=2 y=5 k=3
在乙個長度為6數值為0的數列中:
修改後為0 3 0 0 -3
計算字首和:0 3 3 3 0
從x的位置開始計算+k,在遇到y+1時恢復(+k-k=0)
單點查詢也就是長度為1的區間查詢,不再贅述
操作:1.單點修改
2.查詢平面和
這波直接上**:
void add(int x,int y,int k)
return;
}//在二維平面內單點修改,相信還是看得懂的
int getsum(int x,int y)
return ans;
}//在二維平面內查詢二維字首和,相信也還是看得懂的
由於查詢的是二維字首和,還是要處理一下資料的:printf("%d\n",getsum(x2,y2)+getsum(x1-1,y1-1)-getsum(x2,y1-1)-getsum(x1-1,y2));
字首和處理成平面和的方法與處理成區間和的方法大同小異,就不再說了 樹狀陣列模版
1.一維樹狀陣列 獲得2 k public static int lowbit int i 修改結點 public static void add int i,int value 求和 public static int getsum int i return sum 2.二維樹狀陣列 public...
樹狀陣列模版
單點更新,區間求和 include include using namespace std const intmaxn 1e6 1 inta maxn c maxn intmaxnum 1e6 intlowbit intx intsum intx return res void add intx,i...
樹狀陣列模版
原來聽到樹狀陣列這名字感覺很難,很高大上。學了一下發現不難。而且很好。普通的陣列修改某個值耗費為o 1 輸出和為o n 而樹狀陣列為o logn lowbit x 返回的是x二進位制最後一位1的位置 有公式 cn a n a k 1 an 其中 k 為 n 的二進位制表示中從右往左數的 0 的個數 ...