[bzoj4239]巴士走读
设f[i][j]表示第i个点在第j个时间从1到达的最晚出发时间,有转移方程$f[i][j]=max(f[to][x])(j\ge y)$,然而显然不能暴力转移。但通过这个可以发现f[i][j]的答案与j的大小没有直接关系,而是与能走哪些边有关。
于是,将询问和每一个点边的y排序后,发现一条边如果之前搜过,那么就不用搜了,同时还需要维护出每一个点到终点的最晚出发时间,暴力搜索即可,时间复杂度即边数(每条边只走一次)。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 struct ji{ 5 int x,y,t1,t2; 6 bool operator <(const ji &a)const{ 7 return a.t2<t2; 8 } 9 }a[N*3]; 10 struct ji2{ 11 int nex,to,t1,t2; 12 }edge[N*6]; 13 int E,n,m,t,head[N],f[N],id[N],q[N],ans[N]; 14 bool cmp(int x,int y){ 15 return q[x]<q[y]; 16 } 17 void add(int x,int y,int t1,int t2){ 18 edge[E].nex=head[x]; 19 edge[E].to=y; 20 edge[E].t1=t1; 21 edge[E].t2=t2; 22 head[x]=E++; 23 } 24 void dfs(int k,int t){ 25 f[k]=max(f[k],t); 26 for(int i=head[k];i!=-1;i=edge[i].nex){ 27 if (t<edge[i].t2)return; 28 head[k]=i; 29 dfs(edge[i].to,edge[i].t1); 30 } 31 head[k]=-1; 32 } 33 int main(){ 34 scanf("%d%d",&n,&m); 35 memset(head,-1,sizeof(head)); 36 for(int i=1;i<=m;i++)scanf("%d%d%d%d",&a[i].x,&a[i].y,&a[i].t1,&a[i].t2); 37 sort(a+1,a+m+1); 38 for(int i=1;i<=m;i++)add(a[i].y,a[i].x,a[i].t1,a[i].t2); 39 head[1]=-1; 40 scanf("%d",&m); 41 for(int i=1;i<=m;i++)scanf("%d",&q[i]); 42 for(int i=1;i<=m;i++)id[i]=i; 43 sort(id+1,id+m+1,cmp); 44 f[1]=-1; 45 for(int i=1;i<=m;i++){ 46 dfs(n,q[id[i]]); 47 ans[id[i]]=f[1]; 48 } 49 for(int i=1;i<=m;i++)printf("%d\n",ans[i]); 50 }