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,可以发现这是最大值。
一个点可以被经过多次!
使用C++的选手请注意:
如果DFS爆栈请使用Visual C++编译,并在开头加上
1
#pragma comment(linker, "/STACK:10240000,10240000")
数据已加强
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
题解
使模最大就是找某条路径上的严格次大值,由于一个点可以通过多次,那门可以tarjan缩点,处理出每个联通快的最大值与次小值,剩下就是在DAG图上bfs计算答案。(注意次小值需在最大值路径上)
代码
#include<bits/stdc++.h>
#define mod 998244353
#define inv 499122177
#define M 2000005
typedef __float128 F;
typedef long long ll;
using namespace std;
inline int read()
{
int x=0;char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x;
}
int cnt,tot,ret[M],Next[M],E1[400005],E2[400005],Head[400005];
struct node{int to,next,from,pre;}e[M];
int N,n,m,Q,S,bl[400005],stk[400005],top;
int low[400005],dfn[400005],tim,a[400005];
bool inq[400005],flag[400005],vis[400005];
int mx1[400005],mx2[400005],du[400005],mx3[400005];
inline void ins(int u,int v){ret[++tot]=v;Next[tot]=Head[u];Head[u]=tot;}
void update(int x,int t)
{
if (x==mx1[t]||x==mx2[t]) return;
if (x>mx1[t]){mx2[t]=mx1[t];mx1[t]=x;}
else if (x>mx2[t]&&x!=mx1[t]){mx2[t]=x;}
}
void tarjan(int now)
{
low[now]=dfn[now]=++tim;
stk[++top]=now;inq[now]=1;
for (int i=Head[now];i;i=Next[i])
if (!dfn[ret[i]])
{
tarjan(ret[i]);
low[now]=min(low[now],low[ret[i]]);
}
else if (inq[ret[i]]) low[now]=min(low[now],low[ret[i]]);
if (low[now]==dfn[now])
{
N++;
while (stk[top+1]!=now)
{
bl[stk[top]]=N;
update(a[stk[top]],N);
inq[stk[top]]=0;
top--;
}
}
}
void insert(int u,int v)
{
e[++cnt].to=v;
e[cnt].from=u;
e[cnt].pre=E2[v];
e[cnt].next=E1[u];
E1[u]=cnt;
E2[v]=cnt;
}
void bfs()
{
queue<int>q;q.push(bl[S]);vis[bl[S]]=1;
while (!q.empty())
{
int now=q.front();q.pop();flag[now]=1;
for (int i=E1[now];i;i=e[i].next)
{
du[e[i].to]++;
if (vis[e[i].to]) continue;
vis[e[i].to]=1;
q.push(e[i].to);
}
}
q.push(bl[S]);
while (!q.empty())
{
int u=q.front();q.pop();
for (int i=E2[u];i;i=e[i].pre)
{
int v=e[i].from;
if (!flag[v]) continue;
if (mx1[v]>mx1[u])
{
mx3[u]=mx1[u];
mx1[u]=mx1[v];
}
else if (mx1[v]<mx1[u]&&mx1[v]>mx3[u]) mx3[u]=mx1[v];
if (mx3[v]>mx1[u])
{
mx3[u]=mx1[u];
mx1[u]=mx3[v];
}
else if (mx3[v]<mx1[u]&&mx3[v]>mx3[u])mx3[u]=mx3[v];
}
for (int i=E1[u];i;i=e[i].next)
{
int v=e[i].to;
if (!flag[v]) continue;
mx2[v]=max(mx2[v],mx2[u]);
if (mx1[u]!=mx1[v])mx2[v]=max(mx2[v],min(mx1[u],mx1[v]));
else mx2[v]=max(mx2[v],max(mx3[u],mx3[v]));
du[e[i].to]--;
if (du[e[i].to]==0) q.push(e[i].to);
}
}
}
int main()
{
freopen("1.in","r",stdin);
freopen("test.out","w",stdout);
n=read();m=read();Q=read();S=read();
for (int i=1;i<=n;i++) a[i]=read();
for (int i=1;i<=m;i++)
{
int u=read(),v=read();
ins(u,v);
}
for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i);
for (int i=1;i<=n;i++)
for (int j=Head[i];j;j=Next[j])
if (bl[i]!=bl[ret[j]]) insert(bl[i],bl[ret[j]]);
for (int i=1;i<=N;i++) mx3[i]=mx2[i];
bfs();
while (Q--)
{
int x=read();
if (!flag[bl[x]]) printf("-1 ");
else printf("%d ",mx2[bl[x]]);
}
return 0;
}