[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 }
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/11337699.html