前往大都會

2022-06-23 23:09:18 字數 2855 閱讀 9381

簡單的圖論題。

第一問顯然答案是最短路。

第二問中,由於有旅行路程最短的限制,旅行的過程一定在最短路dag上。

建立最短路dag。(dag的條件非常重要)

每條鐵路會被不在最短路dag上的所有邊分割成若干個片段。

考慮dp,設\(f_i\)表示從源點到達\(i\)的最小代價。

可以列舉\(i\)所在的所有鐵路線上的點\(j\)進行轉移。

把被分割的鐵路線進行字首和,設為\(s\)。

則\(f_i=\min(f_j+(s_i-s_j)^2)\)

直接做時間複雜度是\(o(n^2)\)的。

73分**如下:

#includeusing namespace std;

#define int long long

#define n 1000010

int n,m,h[n],w[n*2],v[n*2],nxt[n*2],ec,d[n],vi[n],tp,st[n],du[n],ct,cc,cv,po[n],ii[n];

struct nn;

struct hl;

int operator <(nn x,nn y)

priority_queueq;

queuetq;

vectors[n],t[n],g[n],vt[n],p[n],id[n];

void dij());

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

d[i]=1e18;

while(!q.empty()));

} }}

void tt() }}

void dd()

c++;

} }}void add(int x,int y,int z)

signed main()

scanf("%lld",&a);

g[i].push_back(a);

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

for(int j=0;j+1但是發現\(f_j+(s_i-s_j)^2=f_j+s_i^2-2*s_i*s_j+s_j^2=(s_i^2)+(-2s_i)s_j+(f_j+s_j^2)\)

後面是直線方程,顯然可以使用凸包維護。

維護\(m\)個凸包,按照拓撲序列舉當前點。

列舉當前點所在鐵路(設為陣列\(a\)),在\(a\)對應的凸包上查詢得到當前點的\(f\)

然後把查詢得到結果插入\(a\)對應的凸包中。

由於\(s\)是單調遞增的,所以可以線性維護凸包。

時間複雜度\(o(m\log_2n)\),瓶頸在最短路。

#includeusing namespace std;

#define int long long

#define n 1000010

int n,m,h[n],w[n*2],v[n*2],nxt[n*2],ec,d[n],vi[n],tp,st[n],du[n],ct,cc,cv,po[n],ii[n];

struct nn;

struct noa[n];

int va(no x,int y)

int cp(no j,no k,no i)

struct hl

while(s.size()>1&&cp(s[s.size()-2],s.back(),x))

s.pop_back();

s.push_back(x);

} int qu(int x)

return -2*s.back().x*x+s.back().y+x*x;

}}bl[n];

int operator <(nn x,nn y)

priority_queueq;

queuetq;

vectors[n],t[n],g[n],vt[n],p[n],id[n];

void dij());

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

d[i]=1e18;

while(!q.empty()));

} }}

void tt() }}

void dd()

c=0;

for(int j=0;jc++;

} }}void add(int x,int y,int z)

signed main()

scanf("%lld",&a);

g[i].push_back(a);

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

for(int j=0;j+1add(g[i][j],g[i][j+1],vt[i][j]);

dij();

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

for(int k=la;k<=j;k++)

s[cc].resize(p[cc].size());

for(int k=0;k+1s[cc][k+1]=s[cc][k]+vt[i][k+la];

la=j+1;

}} cc++;

for(int k=la;kp[cc].push_back(g[i][k]);

for(int k=la;ks[cc].resize(p[cc].size());

for(int k=0;k+1s[cc][k+1]=s[cc][k]+vt[i][k+la];

} printf("%lld ",d[n]);

memset(h,0,sizeof(h));

ec=0;

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

for(int j=0;j+1if(d[g[i][j+1]]==d[g[i][j]]+vt[i][j])

tt();

dd();

printf("%lld ",d[n]);

}