BZOJ2733 永無鄉 線段樹合併

2022-03-26 19:56:19 字數 1644 閱讀 4347

永無鄉包含 n 座島,編號從 1 到 n,每座島都有自己的獨一無二的重要度,按照重要度可 以將這 n 座島排名,名次用 1 到 n 來表示。某些島之間由巨大的橋連線,通過橋可以從乙個島 到達另乙個島。如果從島 a 出發經過若干座(含 0 座)橋可以到達島 b,則稱島 a 和島 b 是連 通的。現在有兩種操作:b x y 表示在島 x 與島 y 之間修建一座新橋。q x k 表示詢問當前與島 x連通的所有島中第 k 重要的是哪座島,即所有與島 x 連通的島中重要度排名第 k 小的島是哪 座,請你輸出那個島的編號。 

輸入檔案第一行是用空格隔開的兩個正整數

n 和 m,分別 表示島的個數以及一開始存在的橋數。接下來的一行是用空格隔開的 n 個數,依次描述從島 1 到島 n 的重要度排名。隨後的 m

行每行是用空格隔開的兩個正整數 ai 和 bi,表示一開始就存 在一座連線島 ai 和島 bi

的橋。後面剩下的部分描述操作,該部分的第一行是乙個正整數 q, 表示一共有 q 個操作,接下來的 q

行依次描述每個操作,操作的格式如上所述,以大寫字母 q 或b 開始,後面跟兩個不超過 n 的正整數,字母與數字以及兩個數字之間用空格隔開。 對於

20%的資料 n≤1000,q≤1000

對於 100%的資料 n≤100000,m≤n,q≤300000 

對於每個 q x k 操作都要依次輸出一行,其中包含乙個整數,表 示所詢問島嶼的編號。如果該島嶼不存在,則輸出-1。

線段樹合併模板題。

對每個島先建一顆權值線段樹(只有logn長度的一條鏈),樹上節點維護權值為[l,r]的島的個數。

對於要建橋但不聯通的島要合併權值線段樹。

合併操作:

x y代表要合併的兩棵樹的節點,若x*y==0,則x或y或x&y不存在,即子樹不需要合併權值,不需改動,直接將父節點指向該節點;

否則將y的權值加到x上,還用root[x]這棵樹,可以減少空間複雜度,然後遞迴merge()。siz[x]+=siz[y];  等效 siz[x]=siz[lc[x]]+siz[rc[x]];  分別為直接合併、由子樹更新(子樹可能僅改了指向)

查詢kth:

同平衡樹,在權值線段樹上二分即可,如果k<=siz[lc[rt]],說明kth在左子樹,反之kth在右子樹且在右子樹的排名為k-siz[lc[rt]]  (這不同於平衡樹因為線段樹的節點含義不同)

用並查集維護聯通關係即是否已合併權值線段樹。

#include#include

#include

#define reg register

#define f(i,a,b) for(i=a;i<=b;++i)

using

namespace

std;

int lc[2000005],rc[2000005],rk[100005],fa[100005],siz[2000005],rt[100005

],o;

int find(int

x)void insert(int &root,int l,int r,int

w)int merge(int x,int

y)int ask(int rt,int l,int r,int

k)void merge2(int x,int

y)int

main()

return0;

}

bzoj2733 永無鄉 線段樹合併

這道題是一道經典的平衡樹 啟發式合併吧。那麼考慮用可持久化線段樹來寫。對每乙個節點儲存一棵線段樹表示所在塊的編號的集合 因此可以乙個塊值儲存一棵樹 然後合併的時候就地櫃合併左子節點和右子節點,然後更新節點的值即可。時空複雜度o nlogn ac 如下 include include include ...

BZOJ 2733 永無鄉 線段樹合併

time limit 10 sec memory limit 128 mb submit 3624 solved 1937 submit status discuss 永無鄉包含 n 座島,編號從 1 到 n,每座島都有自己的獨一無二的重要度,按照重要度可 以將這 n 座島排名,名次用 1 到 n ...

BZOJ2733 永無鄉 splay啟發式合併

作者部落格 永無鄉包含 n 座島,編號從 1 到 n,每座島都有自己的獨一無二的重要度,按照重要度可 以將這 n 座島排名,名次用 1 到 n 來表示。某些島之間由巨大的橋連線,通過橋可以從乙個島 到達另乙個島。如果從島 a 出發經過若干座 含 0 座 橋可以到達島 b,則稱島 a 和島 b 是連 ...