[vijos P1880]ファーラの力
据说这是一道 JOI 的题?反正我觉着挺好的喵~
题目看起来十分可怕,但是代码还是很短的
显而易见的,ans 因分为3个部分:1.中途增加光压的时间 2.中途减少光压的时间 3. 所有路程的总时间
发现如果把每个柱子的光压下限0去掉后,光压无论在何时加都是一样的
因为若从某刻光压小于等于0后,我们可以按需调整光压,就不再出现人为降低光压这个操作,而不论如何最后的光压一定是 E[终点]
所以
1.光压无论在何时加都是一样的
而我们又发现在路径上减少1个光压和在光柱上人为调整1个光压的时间是一样的
光压差就是时间差
我们用dist[n]表示到点n时的光压
2.X-dist[终点]=中途减少光压的时间+所有路程的总时间
又由1得E[终点]-dist[终点]=中途增加光压的时间
这两个式子都是随着dist[终点]的递增而递减的
只要算出最大的dist[终点]即可,这就是为什么要用最短路稍的原因
ans=(X-dist[终点])+(E[终点]-dist[终点)=X+E[终点]-2*dist[终点]
1 #include <cstdio> 2 #include <queue> 3 #include <algorithm> 4 typedef std::pair<long long, int> node; 5 const long long INF=0x7FFFFFFFFFFFFFLL; 6 const int sizeOfPoint=100001; 7 const int sizeOfEdge=600006; 8 9 struct edge {int point, dist; edge * next;}; 10 edge memory[sizeOfEdge], * port=memory; 11 edge * e[sizeOfPoint]; 12 inline edge * newedge(int point, int dist, edge * next) 13 { 14 edge * ret=port++; 15 ret->point=point; ret->dist=dist; ret->next=next; 16 return ret; 17 } 18 19 int N, M, X; 20 int E[sizeOfPoint]; 21 long long dist[sizeOfPoint]; 22 std::priority_queue<node> q; 23 inline long long min(long long x, long long y) {return x<y?x:y;} 24 inline int getint(); 25 inline void putint(long long); 26 27 int main() 28 { 29 N=getint(), M=getint(), X=getint(); 30 for (int i=1;i<=N;i++) E[i]=getint(); 31 for (int i=0;i<M;i++) 32 { 33 int A, B, T; 34 A=getint(), B=getint(), T=getint(); 35 if (E[A]>=T) e[A]=newedge(B, T, e[A]); 36 if (E[B]>=T) e[B]=newedge(A, T, e[B]); 37 } 38 39 for (int i=1;i<=N;i++) dist[i]=-INF; 40 for (q.push(node(X, 1));!q.empty(); ) 41 { 42 node u=q.top(); q.pop(); 43 if (dist[u.second]!=-INF) continue; 44 dist[u.second]=u.first; 45 for (edge * i=e[u.second];i;i=i->next) 46 q.push(node(min(u.first-i->dist, E[i->point]), i->point)); 47 } 48 49 if (dist[N]==-INF) printf("-1\n"); 50 else putint(X+E[N]-(dist[N]<<1)); 51 52 return 0; 53 } 54 inline int getint() 55 { 56 register int num=0; 57 register char ch; 58 do ch=getchar(); while (ch<'0' || ch>'9'); 59 do num=num*10+ch-'0', ch=getchar(); while (ch>='0' && ch<='9'); 60 return num; 61 } 62 inline void putint(long long num) 63 { 64 char stack[22]; 65 register int top=0; 66 if (num==0) stack[top=1]='0'; 67 for ( ;num;num/=10) stack[++top]=num%10+'0'; 68 for ( ;top;top--) putchar(stack[top]); 69 putchar('\n'); 70 }