集訓隊作業2018 三角形

2022-03-31 15:52:40 字數 2562 閱讀 6923

zhangzy的神題~

考慮沒有樹的限制咋做,問題相當於有一些二元組 \((x, y)\) 和乙個空的序列,每次選乙個二元組填到序列裡面,最小化最大字首和。具體來說,在每個節點放石子相當於兩部,1.放上 \(w_i\) ,2.拿掉 \(\sum w_v\),\(v\) 是 \(i\) 在樹上的兒子,那麼可以看做二元組 \((w_i,-\sum w_v)\) 。

令 \(sum\) 表示一段操作石子數量的增量, \(max\) 表示操作序列的石子數量最大字首和,每次向後新增乙個二元組就相當於 \(sum'=sum+\sum w_v,max'=\max(max,max'+w_i)\) 。事實上二元組也可以用 \((sum,max)\) 的形式表示,即 \((w_i-\sum,w_i)\) ,由上面可以發現這個二元組是可以簡易復合的。我們的問題就是給這些二元組安排乙個優先順序,使得從左到右復合之後 \(max\) 最小。

可以證明,對於二元組 \(a,b\),定義 \(+\) 為復合操作,\(a\) 的優先順序比 \(b\) 高當且僅當 \((a+b).max<(b+a).max\) ,且這樣保證不存在二元組 \(a,b,c\) 滿足 \(a。證明需要進行分類討論:

首先考慮復合順序改變後 \(sum\) 不變,所以可以只考慮復合後的 \(max\) ,顯然 \(max\) 越小越好

對於 \(sum\) 為負的二元組,一定比 \(sum\) 為正的二元組優。

對於 \(sum\) 都為負的二元組, \(max\) 越小的優先順序越高。

對於 \(sum\) 都為正的二元組,\(sum-max\) 越小的優先順序越高。

然後我們就證明了不存在二元組 \(a,b,c\) 滿足 \(a,即可以按照這個優先順序給二元組排序,且這樣最小化最終的 \(max\) 。這樣就解決沒有樹的限制的情況。

考慮有樹的限制,因為每個二元組要所有兒子都放完才能放非常麻煩,所以考慮反轉,改為每個二元組要在祖先放完才能放,那麼二元組就變成了 \((\sum w_v-w_i,\sum w_v)\) 。也就是拿走點 \(i\) 上的石子然後放上其兒子的石子,相當於倒過來做之前的操作。此時每乙個字首還是對應原來的乙個時刻,同樣要最小化最大字首和,但是每乙個點只要其父親放了其就能放,變得容易處理許多。

觀察發現,任意兩個二元組合並以後優先順序至少比之前的乙個二元組優先順序低,所以對於某一時刻優先順序最高的二元組,就算其父親還沒有放,其也會在其父親被放之後馬上被放,所以可以直接將這個二元組與它的父親合併。那麼用乙個堆維護一下當前優先順序最高的二元組,就得到了根的答案的操作序列。

最後有乙個結論,對於任意乙個節點,其答案的操作序列一定是根的操作序列的乙個子串行,這裡不太需要證明,直接從優先順序的角度考慮就好了,所以用線段樹合併維護每乙個子樹裡的操作序列和結合後的答案即可,總複雜度 \(\mathcal o(n\log n)\) 。

code

/*program by mangoyang*/

#pragma gcc optimize("ofast", "inline")

#include#define inf (0x3f3f3f3f)

#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;

vectorvec[n], g[n];

ll w[n], w2[n], ans[n];

int vis[n], pa[n], b[n], c[n], rt[n], fa[n], type, n, cnt;

struct node;

} friend bool operator < (const node &a, const node &b)

} a[n]; sets;

inline int ask(int x)

inline void gao(int x)

namespace seg

inline void ins(int &u, int l, int r, int pos)

inline int merge(int x, int y)

}inline void dfs(int u)

ans[u] = seg::s[rt[u]].y;

}int main()

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

read(w[i]), w2[pa[i]] += w[i], fa[i] = i;

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

s.insert(a[i]);

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

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

a[b[i]] = (node);

dfs(1);

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

printf("%lld ", max(w[i], ans[i] + w[i]));

return 0;

}

UOJ 418 集訓隊作業2018 三角形

418.集訓隊作業2018 三角形 和三角形沒有關係 只要知道兒子放置的順序,就可以直接模擬了 記錄歷史最大值 用乙個pair a,b 之後加上a個,期間最大值為增加b個 合併?a1 a2 a1 a2,max b1,a1 b2 放置順序考慮貪心 比較 a放在b前面 和父親進行合併 當且僅當 c a ...

2018 判定三角形

time limit 3 second memory limit 2 mb 輸入三個正整數,若能用這三個數作為邊長組成三角形,則判斷三角形的形狀,如果是等邊三角形就輸出 db 如果是等腰三角形就輸出 dy 否則就輸出 yb 如果不能構成三角形則輸出can t。輸入檔案只有一行,內容為三個正整數,如3...

求大三角形中三角形個數

一道筆試程式設計題要求求乙個大三角形中所有小三角形的個數,大約是下面這種情況 首先想到是的將問題由求邊長為n的三角形個數 求邊長為n 1的三角形個數 求邊長為1的三角形個數 1,回溯求得所有三角形個數。但是再仔細一看因為有重疊三角形和倒置的三角形,所以這個方法不可行。接著找到三角形個數由三部分組成 ...