正题
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3482
题目大意
一张有向图有正整数边权也有xxx边权。其中xxx可以取任何值(但是要注意所有的xxx边必须长度相等),每次询问求SSS到TTT的可能最短路长度个数和它们的和。
解题思路
分层图,第iii层第jjj个点表示SSS到iii的最短路且经过了jjj条xxx的边方案,然后跑最短路。
现在我们定义fif_ifi表示SSS到EEE经过iii条边xxx边的最短路,然后设xxx边的长度为xxx。
那么经过iii条边为最短路的情况当且仅当fi+i∗xf_i+i*xfi+i∗x最小。那么我们可以定义若干条一次函数y=fi+i∗xy=f_i+i*xy=fi+i∗x,那么就是一条以fif_ifi为截距,iii为斜率的线。那么我们考虑y=fi+i∗xy=f_i+i*xy=fi+i∗x为最短路的可能情况。
维护一个y=fi+i∗xy=f_i+i*xy=fi+i∗x的凸包,维护一个单调队列,让剩下的线的两两之间的交点的xxx坐标递增即可。
然后就可以算出第一问,对于第二问用等差数列计算即可。
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#include<queue>
#define ll long long
#define p(a1,a2) ((a2)*n+a1)
using namespace std;
const ll N=510,M=10100,inf=1e18;
struct node{ll to,next,w;
}a[M*2];
struct line{double x,y;
}l[N];
ll n,m,ls[N*N],f[N*N],tot,Q,num,ans,next[N];
double ata[N];bool v[N*N];
queue<ll> q;
void addl(ll x,ll y,ll w)
{a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;a[tot].w=w;
}
ll read() {ll x=0,f=1; char c=getchar();if(c=='x') return -1;while(!isdigit(c)) {if(c=='x')f=-f;c=getchar();}while(isdigit(c)) x=(x<<1)+(x<<3)+c-48,c=getchar();return (!f)?-1:x;
}
void spfa(ll s)
{memset(v,0,sizeof(v));memset(f,127,sizeof(f));q.push(s);v[s]=1;f[s]=0;while(!q.empty()){ll x=q.front();q.pop();ll c=(x-1)/n;if(c==n) continue;for(ll i=ls[(x-1)%n+1];i;i=a[i].next){ll y=p(a[i].to,c+(a[i].w==-1));if(f[x]+max(a[i].w,0ll)<f[y]){f[y]=f[x]+max(a[i].w,0ll);if(!v[y]){v[y]=1;q.push(y);}}}v[x]=0;}return;
}
double gtan(double x1,double y1,double x2,double y2)
{return (y2-y1)/(x1-x2);}
int main()
{n=read();m=read();for(ll i=1;i<=m;i++){ll x,y,w;x=read();y=read();w=read();if(x==y) continue;addl(x,y,w);}Q=read();while(Q--){ll s=read(),t=read();bool flag=0;spfa(p(s,0));for(ll i=0;i<=n;i++)if(f[p(t,i)]<inf){flag=1;break;}if(!flag) {printf("0 0\n");continue;}if(f[p(t,0)]>inf) {printf("inf\n");continue;}ll num=0,sum=0,cnt=0;for(ll i=n;i>=0;i--){if(f[p(t,i)]>inf) continue;while(cnt>=1&>an(l[cnt].x,l[cnt].y,i,f[p(t,i)])<=ata[cnt]) cnt--;l[++cnt]=(line){i,f[p(t,i)]};if(cnt>1) ata[cnt]=gtan(l[cnt-1].x,l[cnt-1].y,l[cnt].x,l[cnt].y);}for(ll i=1;i<cnt;i++){ll L=(int)ata[i]+1,R=(int)ata[i+1];if(L<=R) sum+=(ll)(L*l[i].x+l[i].y+R*l[i].x+l[i].y)*(R-L+1)/2;}num=(ll)ata[cnt];if(ata[cnt]!=num||cnt==1) num++,sum+=f[p(t,0)];printf("%lld %lld\n",num,sum);}
}