題解洛谷 P2659 美麗的序列

2022-10-09 07:39:12 字數 1181 閱讀 6608

看到題解區基本全是單調棧,我來乙個不同的思路——用並查集來貪心。

這是乙個比較經典的 trick,常用來批量處理一條鏈/一棵樹上路徑的最大或最小值問題,大致的思路是按順序列舉每一條邊,並查集維護連通塊來算貢獻。

具體到本題,我們可以把數列抽象成一條 \(n+1\) 點 \(n\) 邊的鏈,\(i\) 與 \(i+1\) 之間的邊權為 \(a_i\)。同時初始化乙個有 \(n+1\) 個點的並查集,需要記錄每個集合的大小。

考慮一條邊做出貢獻的條件是什麼,就是這條邊是路徑上邊權最小的。因此我們將所有邊按邊權從大到小排序,然後按順序列舉每一條邊,根據它連線的兩個連通塊的大小和它的邊權計算貢獻,之後把這條邊加到圖中(也就是合併它連線的兩個連通塊)。

由於我們按邊權降序列舉,顯然在加入一條邊時,過這條邊的每條路徑的最小邊權都由這條邊貢獻。

時間複雜度為 \(\mathcal(n\log n)\),開 o2 可過。

//by: luogu@rui_er(122461)

#include #define rep(x,y,z) for(int x=y;x<=z;x++)

#define per(x,y,z) for(int x=y;x>=z;x--)

#define debug printf("running %s on line %d...\n",__function__,__line__)

#define fileio(s) dowhile(false)

using namespace std;

typedef long long ll;

const int n = 2e6+5;

int n, a[n];

vector> e;

templatevoid chkmin(t& x, t y)

templatevoid chkmax(t& x, t y)

struct dsu

int find(int x)

bool merge(int x, int y)

}dsu;

int main() );

ll ans = 0;

for(auto i : e)

printf("%lld\n", ans);

return 0;

}

這個 trick 還是很有用的,我遇到過好多次,感興趣的話可以做一下這些題:

洛谷 P2659 美麗的序列

單調棧維護區間最小值,單調遞增棧維護區間最小值,考慮當前數對答案的貢獻,不斷加入數,如果加入的數 棧頂,說明棧頂的元素對當前數所在區間是有貢獻的,同時加入當前的數。反之,若當前加入的數比棧頂元素小,那麼棧頂元素 所謂的最小值 已經失去了價值,因為他不會再對後面的區間造成影響,所以彈出棧頂,同時更新 ...

洛谷P2659 美麗的序列

題目 該題目可以用輔助陣列l i r i 來指向以data i 為最小值的左端點和右端點。然後最後列舉每個data i 尋找每個data i 的美麗值的最大值。然後輔助陣列可以用單調棧求出。include include include include include include define ...

洛谷P2659 美麗的序列

gd是乙個熱衷於尋求美好事物的人,一天他拿到了乙個美麗的序列。為了研究這個序列的美麗程度,gd定義了乙個序列的 美麗度 和 美麗係數 對於這個序列的任意乙個區間 l,r 這個區間的 美麗度 就是這個區間的長度與這個區間的最小值的乘積,而整個序列的 美麗係數 就是它的所有區間的 美麗度 的最大值。現在...