[loj3156]回家路线
令$dp[i]$表示经过第$i$条边后的最小烦躁值,有$且dp[i]=\min_{y_{j}=x_{i}且q_{j}\le p_{i}}dp[j]+f(p_{i}-q_{j})$,其中$f(x)=Ax^{2}+Bx+C$
由于$p_{j}<q_{j}\le p_{i}$,按$p_{i}$从小到大枚举,当$q_{j}\le p_{i}$时将信息记在$y_{j}$上,求$dp[i]$时枚举$x_{i}$上的信息即可,复杂度$o(m^{2})$
将后面的式子拆开,提出与$j$无关的部分,即$且dp[i]=f(p_{i})+\min_{y_{j}=x_{i}且q_{j}\le p_{i}}-2Ap_{i}q_{j}+(dp[j]+Aq_{j}^2-Bq_{j})$
将后半部分看作$F_{j}(x)=-2Aq_{j}x+(dp[j]+Aq_{j}^2-Bq_{j})$的直线,对每一个点用凸包来维护这些直线,利用斜率$q_{j}$和询问$p_{i}$的单调性可以做到均摊$o(1)$
复杂度计算:每一条直线插入/询问一次,插入/删除均摊均为$o(1)$,总复杂度$o(m)$;对$p_{j}\le p_{i}<q_{j}$的直线维护一个$set$,复杂度为$o(m\log m)$(对$q$排序可以做到$o(m)$,但排序复杂度也为$o(m\log m)$)
View Code
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 200005 4 #define k(i) -2*A*e[i].q 5 #define b(i) (dp[i]+A*e[i].q*e[i].q-B*e[i].q) 6 struct ji{ 7 int x,y,p,q; 8 }e[N]; 9 vector<int>v[N]; 10 set<pair<int,int> >s; 11 int n,m,A,B,C,ans,sz[N],dp[N]; 12 bool cmp(ji x,ji y){ 13 return x.p<y.p; 14 } 15 double point(int x,int y){ 16 if (k(x)==k(y)){ 17 if (b(x)==b(y))return 0; 18 if (b(x)<b(y))return 0x3f3f3f3f; 19 return -0x3f3f3f3f; 20 } 21 return 1.0*(b(y)-b(x))/(k(x)-k(y)); 22 } 23 void add(int x){ 24 int k=e[x].y; 25 while ((sz[k]>1)&&(point(v[k][sz[k]-2],v[k][sz[k]-1])>point(v[k][sz[k]-1],x))){ 26 v[k].erase(--v[k].end()); 27 sz[k]--; 28 } 29 v[k].push_back(x); 30 sz[k]++; 31 } 32 int query(int x){ 33 int k=e[x].x; 34 if (!sz[k])return 0x3f3f3f3f; 35 while ((sz[k]>1)&&(point(v[k][0],v[k][1])<e[x].p)){ 36 v[k].erase(v[k].begin()); 37 sz[k]--; 38 } 39 return k(v[k][0])*e[x].p+b(v[k][0]); 40 } 41 int main(){ 42 freopen("route.in","r",stdin); 43 freopen("route.out","w",stdout); 44 scanf("%d%d%d%d%d",&n,&m,&A,&B,&C); 45 for(int i=1;i<=m;i++)scanf("%d%d%d%d",&e[i].x,&e[i].y,&e[i].p,&e[i].q); 46 sort(e+1,e+m+1,cmp); 47 e[0].y=1; 48 s.insert(make_pair(0,0)); 49 for(int i=1;i<=m;i++){ 50 while ((s.size())&&((*s.begin()).first<=e[i].p)){ 51 add((*s.begin()).second); 52 s.erase(s.begin()); 53 } 54 dp[i]=query(i)+A*e[i].p*e[i].p+B*e[i].p+C; 55 s.insert(make_pair(e[i].q,i)); 56 } 57 ans=0x3f3f3f3f; 58 for(int i=1;i<=m;i++) 59 if (e[i].y==n)ans=min(ans,dp[i]+e[i].q); 60 printf("%d",ans); 61 return 0; 62 }