1. 程式人生 > 實用技巧 >[loj3156]回家路線

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