傳送門
線段樹維護最小生成樹。兩個結點合併就是把兩個結點之間的兩條橫邊加上後形成乙個環,然後剪掉環上的最大值即可得到當前最小生成樹。(不會證)
於是現在只需要考慮怎麼找最大值。
首先這個環一定是如下構成:兩邊是左節點的最右豎邊和右節點的最左豎邊,然後中間是所有的上下兩行橫邊。如下圖紅色部分。
那麼發現維護每個節點的最右(左)豎邊及其右(左)邊的最大值即可。
然而,如果左邊只剩下了一條豎邊,而最大值又恰巧是這條邊,那麼刪去這條邊之後,左邊就只剩下了橫邊,新節點的左右豎邊就要用右節點的豎邊更新。同時,我們還要找左節點的橫邊中的最大值,來更新新節點的最左豎邊及其左邊最大值。右邊只剩一條邊的情況同理。
總之,要分類討論一些東西,草稿紙上畫一畫就很明白了。
整理一下,每個節點維護的是它所對應區間的最小生成樹的資訊,維護的東西如下:
l /r
:l/r:
l/r:
節點在序列中的左右端點位置。
l _v
al/r
_val
:l\_val/r\_val:
l_val/
r_va
l:節點的最左/右豎邊權值。
r ow
_max
:row\_max:
row_ma
x:節點中橫邊的最大值。
c nt
:cnt:
cnt:
節點中豎邊個數(特判上述特殊情況用)
l _m
ax/r
_max
:l\_max/r\_max:
l_max/
r_ma
x:節點中最左/右豎邊及其左/右邊部分所有邊權的最大值。
s um
:sum:
sum:
節點維護的最小生成樹的邊權和。
注意這裡我記錄的行是0
00和1
11,輸入的行是1
11和2
22,要記得減一…
#include
#define lc (root<<1)
#define rc (root<<1|1)
#define mid (t[root].l+t[root].r>>1)
using
namespace std;
const
int maxn=
6e4+10;
int n,m,row[2]
[maxn]
,clm[maxn]
;int xa,ya,xb,yb,w,l,r;
char op[10]
;struct node
friend
inline node operator+(
const node &l,
const node &r)
}else
if(r.l_val==del)
}return ret;
}}t[maxn<<2]
;inline
void
build
(int root,
int l,
int r)
inline
void
update_clm
(int root,
int pos)
//pos:(h,pos)->(h,pos+1)
inline
void
update_row
(int root,
int pos)
if(pos<=mid)
update_row
(lc,pos)
;else
update_row
(rc,pos)
; t[root]
=t[lc]
+t[rc];}
inline node query
(int root,
int l,
int r)
inline
intread()
intmain()
}if(op[0]
=='q'
) l=
read()
,r=read()
,printf
("%d\n"
,query(1
,l,r)
.sum);}
}
SDOI2015 道路修建
description 某國有2n個城市,這2n個城市構成了乙個2行n列的方格網。現在該國 有乙個旅遊發展計畫,這個計畫需要選定l r兩列 l r 修建若干條專用道路,使得這兩列之間 包括這兩列 的所有2 r l 1 個城市中每個城市可以只通過專用道路就可以到達這2 r l 1 個城市中的任何乙個城...
SDOI2015 道路修建(線段樹維護連通性)
這道題可以看做是 shoi2008 堵塞的交通的加強版,由於形同模擬不同人的寫法差別很大,強烈建議理解了原理之後自己獨立寫 給乙個 2 m 的網格圖,每次操作支援修改一條邊的權值,和查詢 l,r 含 的最小生成樹 如果做過上面那道題就很容易知道這道題是考 毒瘤的 線段樹 只需要維護8個標記 因寫法而...
bzoj3995 SDOI2015 道路修建
題目鏈結 分析 曲神的題解 曲神表示想要結構體版本的 題解最後給出的就是結構體的 bzoj1018的高階版 一開始看到這道題 好像不是很難,用線段樹維護最小生成樹 update的時候直接判斷上下哪一條橫邊比較小,連線即可 然而一下就發現了bug 存在可能性連線點的上下兩條邊都需要連線 那我們就要深入...