codeforces 864 F

有向图,倍增。
思路:参考大佬的题解
倍增思想,比如求s到t的道路,那么先通过反向图dfs出所有可以到达t的节点。(相当于一棵树)如果s不在其中,输出-1.然后先用正向图的边把st数组初始化一下(用字典序最小的一个)。然后把st[t][0]置为n+1.其他剩余点都保持为0.然后在倍增完成后,如果st[ s ][ TOP ] ==n+1说明x最终可以到达t并且继续走到n+1.(2^TOP>3000).否则st[ s ][ TOP ] ==0说明s根本无法走到t。还有一种情况,st[ s ][ TOP ]!=0且!=n+1。那么就说明s进入了字典序循环中,无法走出。巧妙点就是这个把st[ t ][0]初始置为n+1。

学习了新的方法,对倍增又有了一个深刻的认识哇。

#include<bits/stdc++.h>

using namespace std;
const int MAXN = 3000+5;
int n,m,q;
vector<int>head[MAXN],G[MAXN];//正反向图
int st[MAXN][13];//倍增数组
//询问
struct node
{
    int s,k,id;
    node(int s,int k,int id)
    {
        this->s = s;
        this->k = k;
        this->id = id;
    }
};
vector<node>ask[MAXN];
//dfs找到可以到达t的点
bool vis[MAXN];
void dfs(int u)
{
    vis[u] = 1;
    for(int v : G[u])if(!vis[v])dfs(v);
}
//存答案
int ans[400005];

int main()
{
    scanf("%d%d%d",&n,&m,&q);
    int u,v;
    while(m--)
    {
        scanf("%d%d",&u,&v);
        head[u].push_back(v);
        G[v].push_back(u);
    }
    for(int i = 1; i <= n; ++i)sort(head[i].begin(),head[i].end());
    int s,t,k;
    for(int i = 0; i < q; ++i)
    {
        scanf("%d%d%d",&s,&t,&k);
        ask[t].push_back(node(s,k,i));
    }
    for(int t = 1; t <= n; ++t)
    {
        if(ask[t].size() == 0)continue;
        fill(vis+1,vis+1+n,0);
        dfs(t);
        memset(st,0,sizeof st);
        st[n+1][0] = n+1;
        for(int u = 1; u <= n; ++u)
        {
            if(u == t)st[u][0] = n+1;
            else if(vis[u])
            {
                for(int v : head[u])
                {
                    if(!vis[v])continue;
                    st[u][0] = v;
                    break;
                }
            }
        }
        for(int i = 1; i <= 12; ++i)
            for(int j = 1; j <= n+1; ++j)st[j][i] = st[st[j][i-1]][i-1];
        //查询ask中的询问
        for(node x : ask[t])
        {
            int s = x.s;
            int k = x.k-1;
            int id = x.id;
            if(st[s][12] == n+1)
            {
                for(int i = 0; i <= 12; ++i)
                {
                    if(k & (1<<i))s = st[s][i];
                }
                if(s != n+1)ans[id] = s;
                else ans[id] = -1;
            }
            else ans[id] = -1;
        }
    }
    for(int i = 0; i < q; ++i)
    {
        printf("%d\n",ans[i]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值