Segment 李超線段樹

2022-02-06 05:30:43 字數 2938 閱讀 6140

要求在平面直角座標系下維護兩個操作:

1.在平面上加入一條線段。記第 i 條被插入的線段的標號為 i

2.給定乙個數 k,詢問與直線 x = k 相交的線段中,交點最靠上的線段的編號。

若有多條線段符合要求,輸出編號最小的線段的編號

明顯的線段樹特徵:

1.有固定的 區間長度,(<=39989)

2.插入元素支援合併,(乙個線段可以拆成兩段線段)

所以我們用線段樹來做這道題。

線段樹維護什麼元素開始不太好想。

發現要求乙個交點最靠上的線段的編號,所以類似維護區間最大值,我們可以在每個區間內維護乙個線段(這個線段兩端座標就是l和r,也就是說,恰好放在這個區間內),保證這個線段和x=mid這條豎直的線的交點的縱座標是有史以來最大的。

我們在區間裡記錄下來這個線段的所屬編號(注意不是線段編號,因為真實情況的一條線段可能會被劈成許多段,但是它們本質上還是同乙個線段,在貢獻答案的時候,還是要輸出它們所代表的真實線段的編號的)。

同時用乙個結構體記錄下來每個線段的x1,x2,y1,y2以及所屬編號hao。

注意由於要劈斷,縱座標不一定是整數,所以y1,y2都是double型別的。

struct

duanline[n*20

];struct

nodet[

4*(mod1+10)];

發現不需要build,pushup,pushdown,但是。。。

我們不能將區間原有線段因為中點處的值小了而「一 棒子打死」,它中點左邊或者右邊的值可能還會對答案產生貢獻。

所以最關鍵的是add操作。

1.特判l==r

已經到了乙個點上。

如果該點之前沒有維護線段,直接維護現在的線段。

如果有,選擇縱座標靠上的直線(點),縱座標相同,選擇編號較小的。

2.如果沒有恰好放在區間裡。

如果不過mid,根據與mid關係左右查詢。

如果過mid,劈兩半分別查詢。

3.如果找到了恰好的區間

如果該區間沒有維護線段,維護該線段。

如果有,

①如果中點處新的優,留下新的,把舊的中,稍微大的一半留下(全劣則淘汰),下放到對應的子區間。

②如果中點處值相同。一般情況選擇新的劈斷的下放(省的建線段)。但是當新的編號較小,並且新的線段的右端點的縱座標大於等於舊的,這時就要劈斷舊的,將舊的右半部分下放。(使得mid處一定取得是新的線段,也就是編號較小的)

③如果中點處舊的優,同理。

查詢的時候,直接沿著一條logn的路徑查詢,時刻更新最大值和ans即可。沒有什麼可多說的。

詳見**:(寫的很醜,但是比較容易看懂)

#includeusing

namespace

std;

const

int n=1e5+10

;const

int mod1=39989

;const

int mod2=1e9;

intn;

inthas;

intla;

intcntpool,cntdel;

intdel[n];

struct

duanline[n*20

];inline

int newnode(int x1,int x2,double y1,double

y2)//

取新節點

void dele(int

x)//

刪除節點,**空間

struct

nodet[

4*(mod1+10)];//

樹double lv(int x1,int x2,double y1,double

y2)//

斜率void add(int x,int l,int r,int x1,int x2,double y1,double y2,int

hh)

else

else

if(mx1==mx2)}}

return

; }

//l==r情況

int mid=(l+r)>>1

;

if(x1!=l||x2!=r)

}//find

else

else

else

if(q2>=y2)

}else

if(d1==d2)//

new = old

else

if(q2<=y2)

else}}

else

if(d1//

new < old

else

if(y2>=q2)}}

}//update

}int

ans;

double

zui;

void query(int x,int l,int r,int

to)

else

if(zui==mx)

return

; }

if(!t[x].id)

else

else

if(zui==d1)

}int mid=(l+r)>>1

;

if(to<=mid) query(x<<1

,l,mid,to);

else query(x<<1|1,mid+1

,r,to);

}}int

main()

else

}return0;

}

upda:2018.12.27

其實這個東西叫做李超線段樹

就是每個區間保留最靠上的直線,實現o(log^2n)的複雜度。

好像應用只有模板題?

李超線段樹

首先來看一道題 heoi2013 segment 可以發現的是,實質上某個 x k 處的最大值只有乙個,因此我們需要盡可能減少計算不優的線段。那麼對於兩條線段 a,b a ne b 它們左右端點橫座標相同,就只會產生如下四種情況 從特殊情況出發,每次我們都插入一條 1,n 的線段。如果是前兩條情況,...

李超線段樹

t4正解李超線段樹?不會,滾過來學 貌似思路並不是很難的亞子 我們可以使用權值線段樹!對於每個區間,我們維護乙個最優線段 顯然對於乙個線段完全覆蓋的區間我們才處理 分四種情況討論 直接賦值 直接賦值 直接滾粗 最複雜的情況,我們考慮將覆蓋該區間最長的線段保留為最優線段 欸嘿?怎麼搞呢?其實只需判斷該...

李超線段樹

可以處理二維平面上加入線段,然後查詢單點最大值。首先我們定義乙個區間的最優勢線段,為區間中點值最大的線段,然後我們發現處理詢問,我們只需要將經過的線段樹節點上的最優勢線段對應的點值取max即可。然後考慮如何處理修改,首先將線段劃分到 o logn 個線段樹節點上。如果當前線段被最優勢線段完全覆蓋,那...