金色絲線將瞬間一分為二 樹狀陣列的使用

2021-08-25 08:57:21 字數 3756 閱讀 1609

description

為了解開騎士木乃伊事件,久城一彌和布洛瓦警官來到了停屍間。停屍間裡有n具遺體,每具遺體都有乙個座標(x,y)。

由於停屍間的遺體擺放得橫平豎直,我們認為兩具遺體(xi,yi)和(xj,yj)得距離為|xi-xj|+|yi-yj|。

負責停屍間的工人由於需要經常搬運遺體,所以對任意兩具遺體的距離之和特別有印象。

工人們已經記不得每具遺體對應的是什麼人了。但是它們記得,八年前將公尺莉·馬露的遺體搬進停屍間之後,停屍間的任意兩具遺體的距離之和超過了d。

現在給你工人們將n具遺體搬進停屍間的時間順序,請你找出第一具有可能是公尺莉·馬露的遺體。如果不存在這樣的遺體,請輸出-1。

input

第一行兩個整數n,d,意義如題目描述所示。

接下來n行,按照時間順序給出每具遺體的座標,每行兩個整數x,y。

output

輸出一行乙個整數,表示按照時間順序第一具有可能是公尺莉·馬露的遺體的編號。如果不存在這樣的遺體,輸出-1。

sample input

5 10

1 1

2 2

3 3

4 4

5 5

sample output

4 data constraint

10%的資料保證,n≤500.

40%的資料保證,n≤8000.

60%的資料保證,n≤1e5.

另有10%的資料保證,所有遺體的橫座標x都相同。

另有10%的資料保證,x(i)≤x(i+1),且y(i)≤y(i+1)。

100%的資料保證,n≤6×10^5,0≤d≤1e18,0≤x,y≤1e9.

觀察題目,我們可以知道,題目求的是對於任意的k,使得σ(|xi-xj|+|yi-yj|)>d (1≤i<j≤k),最小的k是多少。

理解題目,可以很容易的知道,若我們前n-1具屍體間的曼哈頓距離之和為f(n-1),則f(n)=f(n-1)+σ(|xi-xn|+|yi-yn|) (1≤i≤n-1)

因此,我們可以知道,對於這樣的函式f(x)必然是乙個單調遞增的函式。

我們重新回頭觀察題目,對於兩個點(xi,yi),(xj,yj),曼哈頓距離 distance=|xi-xj|+|yi-yj|,那麼,我們可以變式為 distance=max(xi,xj)-min(xi,xj)+max(yi,yj)-min(yi,yj)。

而我們再移動一下式子,讓它沒有負號,並消掉一邊的函式符號,過程如下

distance+min(xi,xj)+min(yi,yj)=max(xi,xj)+max(yi,yj)→distance+2×min(xi,xj)+2×min(yi,yj)=max(xi,xj)+min(xi,xj)+max(yi,yj)+min(yi,yj)

經過剛才的過程,我們得到了式子 distance=xi+xj+yi+yj-2×min(xi,xj)-2×min(yi,yj)。

當然,這個式子我們也可以理解成點i,點j以點(0,0)為中轉站,而得到的它們間的曼哈頓距離。

所以,我們就可以得到函式 dis(i,j)=xi+xj+yi+yj-2×min(xi,xj)-2×min(yi,yj)。

使用剛才得到的函式,我們可以將前k個點的任意兩具遺體的距離的和表示成 σdis(i,j) (1≤i<j≤k)。

我們將剛才的函式分成正的和負的兩部分,可以很快發現,我們可以很快的處理出正的部分,例如,對於前k個點,我們在記錄下sum=σ(xi+yi) (1≤i≤k),因為每個點都會和其它(k-1)個點求取距離,所以正的部分應該是 sum×(k-1)。

而負的部分,我們則需進行一下討論。

我們留意一下,可以發現,剛才的函式中,實際上,橫座標和縱座標是分離的,也就是說,它們並不需要一一對應,(xi,yi)與(xj,yj)的距離和(xi,yj)、(xj,yi)的距離是相同的。所以,我們分別研究它們的橫座標x和縱座標y。

首先,我們考慮暴力。對於前k個點,我們可以對它們進行一次排序,然後,對於橫座標的排序中,點i的排名是ri,我們可以知道它的值xi僅僅對後面(k-ri)個點有貢獻,前面的ri-1個點與它比較時,前面點的x值做貢獻。那麼,我們就可以知道,點i所能做的貢獻時 xi×(k-ri),所以,我們可以得到前k個點所作貢獻的大小 σ[xi×(k-ri)] (1≤i≤k)

但是,該方法要不斷重新統計任意兩點間的曼哈頓距離之和,很顯然方法效率並不高, 複雜度達到o(n^2),並且,還要不斷維護乙個有序的數列,因此,並不可取。

根據上面講述過的,函式f(x)具有單調性,其值隨x增大而增大。所以,我們可以考慮不斷求取f(x)的變化值來得到答案。

例如,在正的部分,由於前k個數的和sum=σ(xi+yi) (1≤i≤k),那麼,(k-1)個數的和便是sum=σ(xi+yi) (1≤i≤k-1).

因為,前k個數,正的部分的總和應該是(k-1)sum,也就是(k-1)σ(xi+yi) (1≤i≤k) ,對於前k-1個數,整的部分的總和是 (k-2)σ(xi+yi) (1≤i≤k-1) 。因此,我們做差,(k-1)σ(xi+yi) (1≤i≤k)-(k-2)σ(xi+yi) (1≤i≤k-1)=(k-1)σ(xi+yi) (1≤i≤k-1)+(k-1)(xk+yk)-(k-2)σ(xi+yi) (1≤i≤k-1)=σ(xi+yi) (1≤i≤k-1)+(k-1)(xk+yk).

所以,從前(k-1)個數到前k個數,正的部分的增加的值,是σ(xi+yi) (1≤i≤k-1)+(k-1)(xk+yk)。當然,縱座標y的變化也是同理。

觀察負的部分,我們也尋找它們的變化量。

根據之前的公式 dis(i,j)=xi+xj+yi+yj-2×min(xi,xj)-2×min(yi,yj),很容易想到,我們需要分類討論。

易知,假如當前已經有乙個有序的序列,裡面有(k-1)個數。那麼當我們插入乙個數xk,它當前的排名是rk,那麼,逐漸遞增的序列中,(1~(rk-1))的數都會與xk這個數計算距離,並且,對答案做出貢獻的是前(rk-1)個數。因為在這個序列中,前(rk-1)個數的大小小於xk,所以在取min時前面的數要做出貢獻,而xk不作貢獻。所以,此時負的部分會減少 2σ(xi) (1≤i<k,ri<rk)

另外,在序列中,排名為(rk+1~k)的數,在與xk計算距離時,xk顯然要小於後面的數,因此,xk要做出貢獻。然後,xk產生的貢獻,就是 2×xk×(當前有多少個數大於xk)。

由於負的部分中出現了兩個統計,乙個是統計有多少個數大於xk,另乙個部分是統計小於xk的數的和,我們選擇使用樹狀陣列來解決問題。

當然,選擇線段樹解決問題,答案並不會錯誤,但是由於複雜度的原因,會出現超時的情況。

**如下:

#include 

#define ll long long

using namespace std;

const int maxn=600010;

ll ans,d,sum;

int n,x[maxn],y[maxn],rankx[maxn],ranky[maxn],v[maxn];

struct tree

ll getsum(int i,ll s=0)

ll getnum(int i,ll s=0)

ll calcsum(int left,int right)

ll calcnum(int left,int right)

}xt,yt;

inline bool box(int a,int b)

inline bool boy(int a,int b)

int main()

printf("-1");

return

0;}

多一分陪伴少一分孤獨

多一分陪伴,少一分孤獨 慈母手中線,遊子身上衣 臨前密密縫,意恐遲遲歸 誰言寸草心,報得三春暉。從小就熟背 遊子吟 可是其中滋味遲遲也不能真正體會,自從產房接過小侄子的那一刻,我才真正體會到為人父母的滋味,看到它那懵懂的臉盤,胡亂擺動的小手,那張沒有長牙的小嘴,整顆心都被它融化了,從那刻起相信所有的...

每日筆記(一分耕耘,一分收穫)

堆 存放new出來的物件,可被所有執行緒共享,不會存放別的物件引用 string strs newstring 10 棧 存放基本型別 string strs null1.靜態初始化int a 2.動態初始化int a newint 2 a 0 1 a 1 2 3.陣列的預設初始化陣列是引用型別,它...

一分多行列轉換

問題描述 將以下表方式存放的資料 1 cms8000290693 011101251020006862,2 cms8000692449 9011101012510200105,011201251020000015,041101251020000193,3 cms6000320019 01110125...