codeforces 864 F

来源:互联网 发布:overlay sdn网络分为 编辑:程序博客网 时间:2024/06/05 04:03

有向图,倍增。
思路:参考大佬的题解
倍增思想,比如求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;}