基准时间限制:4 秒 空间限制:524288 KB 分值: 80
lbn是战忽中心——一个绝密的军事组织的一个军官,今天他接到了一个紧急任务:调查敌国X国某些城市的经济情况。
X国有N个城市,由M条单向道路连接,其中S城是X国的首都。
每个城市i有一个发达指数a[i],我们定义城市i的经济状况为首都S到城市i任意一条路径上两个不同的城市x,y的a[x] mod a[y]的最大值。(x和y必须在同一条路径上,x,y可以是i或者S)
lbn当然能轻松地完成这个任务,但他想考考你。
样例解释:
首都为2
2到1只有一条路径,城市1的经济情况为a[2] mod a[1]=23
对于城市3的经济状况,我们可以选择路径2->4->3,并选择城市3 4,经济状况为a[3] mod a[4]=37,可以发现这是最大值。
对于城市4的经济状况,我们可以选择路径2->3->4,并选择城市3 4,经济状况为a[3] mod a[4]=37,可以发现这是最大值。
一个点可以被经过多次!
数据已加强
Input
第一行四个正整数N,M,Q,S
分别表示X国城市数量,城市间有向边的数量,需要调查的城市的数目和首都的编号。每个城市的标号为1到N
第二行N个正整数,其中第i个整数表示a[i]。
第2至M+1行每行两个正整数x,y。表示有一条从城市x到y有向边。
第M+2行Q个正整数,表示需要调查的城市的数目的编号。
数据保证无重边无自环,不会查询首都。
1<=N,Q<=4*10^5
1<=M<=2*10^6
1<=a[i]<=10^9
Output
共一行Q个整数,按询问顺序输出每个城市的经济情况。
如果一个城市不存在任何一条从首都来的路径,则其经济情况输出-1。
Input示例
4 5 3 2
98 23 37 100
2 1
2 4
2 3
3 4
4 3
1 3 4
Output示例
23 37 37
这题细节各种多。。。关键如何在dag上从s到某个点上的次小值,我们设4个量就可以类似dp递推了。
设:
dp[0][v]
d
p
[
0
]
[
v
]
:为从s到v路径上的最大值
dp[1][v]
d
p
[
1
]
[
v
]
:为从s到v路径上的次大值(答案)
dp[2][v]
d
p
[
2
]
[
v
]
:为从s到v路径上经过的所有可能的点的最大值
dp[3][v]
d
p
[
3
]
[
v
]
:为从s到v路径上经过的所有可能的点的次大值
然后通过分类讨论就可以证明他们是可以递推的,即我们选中的答案我们可以保证在s到这个点的某条路径会有某个值严格大于它。
代码:
#include<iostream>
#include<cstdio>
#include<stack>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cmath>
#include<vector>
#include<stack>
#define maxn 400005
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
vector<int>g[maxn],G[maxn];
int DFN[maxn],low[maxn],index;
int st[maxn],cnt;
bool inS[maxn];
int dp[4][maxn];
inline int _min(int a,int b)
{
return a>b?b:a;
}
inline int _max(int a,int b)
{
return a>b?a:b;
}
int be[maxn];
int tot;
int a[maxn];
void tarjan(int v)
{
DFN[v]=low[v]=++index;
st[++cnt]=v;inS[v]=true;
for(int i=0,num=g[v].size();i<num;++i)
{
int u=g[v][i];
if(!DFN[u])
{
tarjan(u);
low[v]=_min(low[v],low[u]);
}
else
if(inS[u])low[v]=_min(low[v],DFN[u]);
}
if(DFN[v]==low[v])
{
++tot;int now;
do
{
now=st[cnt]; --cnt;
be[now]=tot;
inS[now]=false;
if(a[now]>dp[0][tot])dp[1][tot]=dp[0][tot],dp[0][tot]=a[now];
else if(a[now]<dp[0][tot]&&a[now]>dp[1][tot])dp[1][tot]=a[now];
dp[2][tot]=dp[0][tot],dp[3][tot]=dp[1][tot];
}while(now!=v);
}
}
queue<int> que;
void update(int u,int v)//核心是这个函数,好好想想,可以分类讨论证明
{
dp[1][v]=_max(dp[1][v],dp[1][u]);
if(dp[0][v]!=dp[2][u])dp[1][v]=_max(dp[1][v],_min(dp[0][v],dp[2][u]));
else dp[1][v]=_max(dp[1][v],dp[3][u]);
if(dp[2][u]>dp[2][v])dp[3][v]=dp[2][v],dp[2][v]=dp[2][u];
else if(dp[2][v]>dp[2][u]&&dp[2][u]>dp[3][v]) dp[3][v]=dp[2][u];
if(dp[3][u]>dp[2][v])dp[3][v]=dp[2][v],dp[2][v]=dp[3][u];
else if(dp[2][v]>dp[3][u]&&dp[3][u]>dp[3][v])dp[3][v]=dp[3][u];
}
int deg[maxn];
bool vis[maxn];
void bfs(int r)
{
queue<int> que;
que.push(r);
vis[r]=true;
while(que.size())
{
int u=que.front();que.pop();
for(int i=0,num=G[u].size();i<num;++i)
{
int v=G[u][i];
++deg[v];
if(!vis[v])
{
vis[v]=true;
que.push(v);
}
}
}
}
void topo(int r)
{
que.push(r);
while(que.size())
{
int u=que.front();que.pop();
for(int i=0,num=G[u].size();i<num;++i)
{
int v=G[u][i];
update(u,v);
--deg[v];if(!deg[v])que.push(v);
}
}
}
void init(){}
int main()
{
int n,m,q,s;
cin>>n>>m>>q>>s;
init();
for(int i=1;i<=n;++i)
scanf("%d",a+i);
int x,y;
for(int i=0;i<m;i++)
{
scanf("%d%d",&x,&y);
g[x].push_back(y);
}
for(int i=1;i<=n;++i)
if(!DFN[i]) tarjan(i);
// for(int i=1;i<=n;i++)
// cout<<i<<" "<<be[i]<<endl;
for(int u=1;u<=n;++u)
for(int i=0,num=g[u].size();i<num;++i)
{
int v=g[u][i];
if(be[u]!=be[v])
G[be[u]].push_back(be[v]);
}
bfs(be[s]);
topo(be[s]);
while(q--)
{
scanf("%d",&x);
if(vis[be[x]])printf("%d ",dp[1][be[x]]);
else printf("-1 ");
}
return 0;
}