[NOI2019] 回家路线
$solution:$
算法一
通过观察范围发现 $q\leq1000$ ,所以直接暴力拆点 $dp$ 。时间复杂度 $O(1000m)=O(能过)$ 。
算法二
因为有 $A\times x^2+B\times x+C$ 考虑斜率优化。
设 $f_i$ 表示走完第 $i$ 条边的最小烦躁值,则 $f_i=\min\{f_j+A\times (p_i-q_j)^2+B\times (p_i-q_j)+C\}\space (u_i=v_j,p_i\geq q_j)$ 。
可以发现现在的瓶颈是如何快速处理 $u_i=v_j,p_i\geq q_j$。
通过算法一可以得到通过将 $p$ 排序处理顺序,然后就将决策边放入其 $v_j$ 中 。
每次取出 $q$ 值,插入相对应的 $v$ 中既可以找到决策点。
然后就斜率优化即可。
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<queue> #include<climits> using namespace std; inline int read(){ int f=1,ans=0;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } const int MAXN=200001; deque<int> que[MAXN]; int n,m,A,B,C,f[MAXN]; struct node{ int u,v,p,q; }g[MAXN]; vector<int> ve[MAXN]; vector<int> pre[MAXN]; int X(int id){return g[id].q;} int Y(int id){return f[id]+A*g[id].q*g[id].q-B*g[id].q;} void insert(int id){ int ps=g[id].v; while(que[ps].size()>=2){ int las2=que[ps].back();que[ps].pop_back(); int las1=que[ps].back();que[ps].pop_back(); if((Y(las2)-Y(las1))*(X(id)-X(las1))<(Y(id)-Y(las1))*(X(las2)-X(las1))){ que[ps].push_back(las1); que[ps].push_back(las2); break; } que[ps].push_back(las1); }que[ps].push_back(id); // printf("id:%d ps:%d front:%d\n",id,ps,que[ps].front()); } void del(int id){ int ps=g[id].u; while(que[ps].size()>=2){ int las1=que[ps].front();que[ps].pop_front(); int las2=que[ps].front();que[ps].pop_front(); if((Y(las2)-Y(las1))>((X(las2)-X(las1))*2*A*g[id].p)){ que[ps].push_front(las2); que[ps].push_front(las1); break; }que[ps].push_front(las2); }return; } int Minn=INT_MAX; int calc(int G){return A*G*G+B*G+C;} int main(){ freopen("route.in","r",stdin); freopen("route.out","w",stdout); // freopen("1.in","r",stdin); n=read(),m=read(),A=read(),B=read(),C=read(); for(int i=1;i<=m;i++) g[i].u=read(),g[i].v=read(),g[i].p=read(),g[i].q=read(),ve[g[i].p].push_back(i); memset(f,127/3,sizeof(f)); que[1].push_back(0);f[0]=0; for(int i=1;i<=1000;i++){ int Siz=pre[i].size(); for(int j=0;j<Siz;j++) insert(pre[i][j]); Siz=ve[i].size(); for(int j=0;j<Siz;j++){ int id=ve[i][j],ps=g[id].u; // if(i==9){printf("size:%d\n",que[2].size());} del(id); if(que[ps].empty()) continue; f[id]=f[que[ps].front()]+calc(g[id].p-g[que[ps].front()].q); pre[g[id].q].push_back(id); } } // for(int i=1;i<=m;i++) printf("X(%d):%d Y(%d):%d\n",i,X(i),i,Y(i)); // for(int i=1;i<=m;i++) printf("f(%d):%d\n",i,f[i]); for(int i=1;i<=m;i++) if(g[i].v==n) Minn=min(Minn,f[i]+g[i].q); printf("%d\n",Minn);return 0; }