[NOI2019] 回家路线

link

$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;
}
View Code

 

posted @ 2019-07-20 12:01  siruiyang_sry  阅读(448)  评论(1编辑  收藏  举报