ZJOI2019 語言 樹上差分 線段樹合併

2022-05-07 08:18:11 字數 2360 閱讀 3419

loj#3046

題意還是很好懂的,問題也很容易轉化為求每個點能到的點的個數之和,最後除以$2$即可

考慮任意一點i能到的點的個數。這些點所組成的點集等於所有包含節點$i$的鏈的點集的並集。

需要哪些資訊才能維護出這個點集?

由於每條鏈都包含了節點$i$,因此這個點集會組成乙個連通塊(暫且這麼叫吧),這個連通塊顯然可以通過確定其邊界上的點確定下來,那麼問題變為如何維護出連通塊的大小

這就是在考察$dfs$序的應用了,先以$dfs$序建立線段樹。借助於虛樹的思想,我們維護出每乙個區間內選擇了點到$1$號節點的根綴的並集大小,記為$siz$。假設現在我們已知線段樹中乙個區間的左區間資訊與右區間資訊,如何得出這個區間的資訊?直接把左右區間的$siz$相加顯然不對,有重複的部分,重複部分的大小是多少?結合$dfs$序,可以發現重合部分就是左區間選擇的點中$dfs$序最大的點$mx$與右區間選擇的點中$dfs$序最小的點$mn$的$lca$的深度,即$dep[lca(mx, mn)]$,左右區間的$siz$相加再減去這個就是這個就是這個區間的$siz$,而最後的連通塊的大小就是整個序列的$siz$減去$dep[lca(mx, mn)]$,$mx$是整個點集中$dfs$序最大的點,$mn$是$dfs$序最小的點。

為了快速求$lca$可以預處理尤拉序與$rmq$,在$o(1)$內查詢$lca$,資訊更新就是$log$的時間複雜度

我們需要乙個連通塊的邊界,這個邊界顯然是由所有鏈的邊界組成的,因此在樹上差分就可維護出邊界

這是對於乙個點的情況。對於所有的點,因為使用了樹上差分,父親節點需要從兒子節點繼承資訊,於是就需要線段樹合併

總時間複雜度是$o(nlogn)$的

**:

#includeusing

namespace

std;

typedef

long

long

ll;const

int maxn = 100005

;inline

intread()

intn, m, root[maxn];

ll ans;

inthead[maxn], tot;

struct

edgee[maxn

<<1

];void addedge(int x, inty);

head[x] =tot;

}int

f[maxn];

int cur, lg[maxn<<1], st[20][maxn<<1], arr[maxn<<1

], dfn[maxn], dep[maxn];

void dfs1(int x, int

fa)}

void

rmq()

for(int j = 1; j <= lg[cur]; ++j)

for(int i = 1; i + (1

<< j) - 1

<= cur; ++i)

}int get_lca(int x, int

y)int

ndnum, tim;

struct

seg_treetr[maxn*64

];void update(int

x)void modify(int x, int l, int r, int p, int

w)

int mid = (l + r) >> 1

;

if(dfn[p] <=mid)

else

update(x);

}int merg(int x, int y, int l, int

r)

int mid = (l + r) >> 1

; tr[x].ls =merg(tr[x].ls, tr[y].ls, l, mid);

tr[x].rs = merg(tr[x].rs, tr[y].rs, mid + 1

, r);

update(x);

returnx;}

void dfs2(int

x)

ans += (ll)tr[root[x]].siz -dep[get_lca(tr[root[x]].mx, tr[root[x]].mn)];

}int

main()

dfs1(

1, 0

); rmq();

for(int i = 1; i <= n; ++i)

root[i] = ++ndnum;

while(m --)

}dfs2(1);

printf(

"%lld\n

", ans >> 1

);

return0;

}

view code

ZJOI2019 語言 解題報告

3個 log 做法比較簡單,但是寫起來還是有點麻煩的。大概就是樹剖把鏈劃分為 log 段,然後任意兩段可以組成乙個矩形,就是個矩形面積並,聽說卡卡就過去了。好像這個可以被優化到兩個 log 算了,估計挺麻煩的。乙個 log 的做法看起來還挺厲害的。考慮欽定某個點算它的貢獻,於是我們要算的是所有經過它...

ZJOI2019賽季回顧

zjoi2019落下了帷幕 儘管成績不盡如人意 但是明天還會繼續 正如一句話所說 不要害怕落日的黑暗,因為明天的太陽還會照常公升起 總排rank35,僅以此文章回顧整個賽季 不算很難的題,大家都ak了,也沒什麼好說的 day2t1很傻的乙個地方判錯了,丟分,然後剩下兩個暴力,總分194 day2t3...

ZJOI2019一輪遊記

期待已久的省選終於開始了233,關於之前的一些內容,在zjoi2019一輪停課刷題記錄都可以找到,這裡不再贅述 zjoi2019,bless all 今天難得有休息,昨晚修仙到挺晚的,但早上還是起的很早的說 下了個艦b玩玩感覺不錯,挺喜歡的,然後又是雀魂 現在銀間能上分但銅間就狂掉233 下午和cx...