【51Nod1815】调查任务

8 篇文章 0 订阅
6 篇文章 0 订阅

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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值