UNR 1 奇怪的線段樹

2022-03-31 15:52:39 字數 1366 閱讀 3409

一道好題,感覺解法非常自然。

首先我們只需要考慮一次染色最下面被包含的那些區間,因為把無解判掉以後只要染了乙個節點,它的祖先也一定被染了。然後發現一次染色最下面的那些區間一定是一段連續的左兒子+一段連續的右兒子。

證明的話可以看官方題解,感性理解的話不難,同時,任意一段連續的左兒子+右兒子也對應乙個區間。定義乙個左兒子區間 \([l_i,r_i]\) 的後繼是所有 \(r_i=l_i+1\) 的左兒子和右兒子,乙個右兒子區間 \([l_i,r_i]\) 的後繼是所有 \(r_i=l_i+1\) 的右兒子區間,不難發現這是乙個dag。那麼這張圖的一條路徑就對應了原圖的乙個染色區間,也就是要求這個dag的最小路徑覆蓋,優化建圖+上下界最小流即可。

code

/*program by mangoyang*/

#include #define inf (0x7f7f7f7f)

#define max(a, b) ((a) > (b) ? (a) : (b))

#define min(a, b) ((a) < (b) ? (a) : (b))

typedef long long ll;

using namespace std;

template inline void read(t &x)

const int n = 200005, m = 200005;

int l[n], r[n], col[n], low[n], isl[n], n, ns, nt, cnt = 1;

inline void init(int u, int l, int r)

low[u] = col[u] && (!col[lc]) && (!col[rc]);

}namespace flow

inline int bfs()

} return ~dis[t];

} inline int dfs(int u, int flow)

return used;

} inline void setflow(int x, int y)

inline int getflow()

}inline void addedge(int x, int y, int a, int b)

int main()

else if(r[i] < n)

addedge(i + (n << 1), r[i] + 1 + (n << 2), 0, inf);

} flow::setflow(ns, nt);

flow::getflow();

flow::addedge(t, s, inf);

cout << flow::getflow() << endl;

return 0;

}

線段樹 單調棧 UNR 1 爭奪聖杯

用單調棧求出left right 可以發現每個點的貢獻是關於left right的分段函式 然後就是分段函式累加求和 當時打的線段樹 看了題解漲姿勢了 可以差分 做到o n include include includeusing namespace std typedef pairabcd typ...

UOJ 217 UNR 1 奇怪的線段樹

網路流 我們先來推一波性質 1 無解當且僅當乙個節點為0且它的兒子為1,有解的話,只有深度極大的節點是有用的 訪問它祖先一定也訪問了 2 任何乙個區間定位都是一段連續的右兒子 一段連續的左兒子 3 性質2的逆定理成立 實際上,每個右兒子區間左端點一定不同,左兒子區間右端點不同 這意味著每個右兒子後繼...

JZOJ5456 奇怪的佇列 線段樹

題目 給出nn n個人的身高,第i ii個人記得他的前面或者後面有a i a i a i 個人比他高。這些人字典序最小的排列。40分做法 先將所有人的身高排序,然後dfs dfsdf s全排列,再判斷是否成立。時間複雜度 o n n2 o n n 2 o n n2 100分做法 按照樣例一來模擬 4...