洛谷 P3994 高速公路(資料結構斜率優化)

2022-03-01 20:40:39 字數 2735 閱讀 4709

設dp[i] 表示第i個城市到根節點的最小花費

dp[i]=min 

這是o(n^2)的

這個式子可以斜率優化

dp[i]+dis[j]*p[i]=dis[i]*p[i]+q[i]+dp[j]

就是一條斜率為p[i]的直線,截(dis[j],dp[j])的最小截距

在根往下走的過程中,斜率單調遞增

這就體現了 為什麼題目中說「i號城市是j號城市的某個祖先,那麼一定存在pi<=pj」

我們按dfs序dp

現在唯一的問題就是如何得到 乙個點到根節點路徑上的單調佇列

只需要考慮如何去除兄弟節點的子樹對單調佇列的影響

即在乙個節點退出dfs時,將單調佇列恢復為這個節點開始dfs的情況

頭指標只是不斷的+1,沒有涉及到單調佇列中元素的修改,所以記錄下頭指標在哪個位置即可

尾指標涉及到元素的替換,但是它只會替換乙個元素,所以記錄下尾指標的位置,以及被當前點替換的元素是誰

當節點退出dfs時,恢復記錄的這三個值即可

這樣的話,乙個節點多次出隊入隊,時間複雜度就不是o(n)了

所以二分出隊位置,時間複雜度為o(nlogn)

樸素的dp:

#include#include

#include

using

namespace

std;

#define n 1000001typedef

long

long

ll;int

p[n],q[n];

int front[n],to[n<<1],nxt[n<<1],val[n<<1

],tot;

intfa[n];

ll dis[n];

intt;

ll mi[n];

void read(int &x)

}void add(int u,int v,int

w)void dfs(int x,intf)

dfs(to[i],x);

}}int

main()

dfs(

1,0);

for(int i=2;i<=n;++i) cout

;}

view code

斜率優化,暴力出隊:

#include#include

using

namespace

std;

#define n 1000001typedef

long

long

ll;int

front[n],nxt[n],to[n],tot,val[n];

intp[n],q[n];

intq[n],head,tail;

ll dis[n];

ll dp[n];

void read(int &x)

}void add(int u,int v,int

w)inline

double x(int i,int j)

inline

double y(int i,int j)

void dfs(int

x)int

main()

for(int i=front[1];i;i=nxt[i])

for(int i=2;i<=n;++i) cout

;}

view code

斜率優化,二分出隊

#include#include

using

namespace

std;

#define n 1000001typedef

long

long

ll;int

front[n],nxt[n],to[n],tot,val[n];

intp[n],q[n];

intq[n],head,tail;

ll dis[n];

ll dp[n];

void read(int &x)

}void add(int u,int v,int

w)inline

double x(int i,int j)

inline

double y(int i,int j)

void dfs(int

x)

if(tmp!=-1) head=tmp;

else head=tail-1

;

int j=q[head];

dp[x]=(dis[x]-dis[j])*p[x]+dp[j]+q[x];

l=head,r=tail-2,tmp=-1

;

while(l<=r)

if(tmp!=-1) tail=tmp+2

;

else tail=head+1

;

int rr=q[tail];

q[tail++]=x;

for(int i=front[x];i;i=nxt[i])

dis[to[i]]=dis[x]+val[i],dfs(to[i]);

head=now_h; q[tail-1]=rr; tail=now_t;

}int

main()

for(int i=front[1];i;i=nxt[i])

for(int i=2;i<=n;++i) cout

;}

view code

洛谷P3948 資料結構 題解

題目傳送 感覺這道題秀了我一地的智商。審題沒審好,沒確定帶修改的操作中詢問的次數 1000,且max和min都是事先給好 不變的。想了半天線段樹 分塊,卻忘了最基礎的暴力。寫不出題時先寫暴力。離線部分 顯然不能暴力處理詢問了,但是沒有修改,又是區間詢問個數,自然要想到字首和優化了。設sum i 為前...

洛谷P3377 (資料結構 左偏樹)

題意 合併堆及刪除堆中最小元素。思路 採用一般的二叉堆可以實現刪除操作,但是要合併的話就會爆,因此引進了左偏樹這個資料結構,可在logn時間內實現合併操作。左偏樹的性質 1.堆的性質 2.左子節點的距離大於右子節點的距離 正是利用這些性質實現堆的快速合併。如下 其中並查集的路徑壓縮會破壞掉樹的結構,...

洛谷 P3948 資料結構 (差分陣列)

直接差分陣列搞一搞就ok了。因為前面的查詢和修改摻雜在一起的詢問很少,所以對於那些詢問我們暴力去查詢就ok。在final詢問之前求乙個符合要求的字首和就可以o 1 輸出了。include using namespace std const int maxn 8e4 5 typedef long lo...