1 条题解

  • 0
    @ 2017-11-08 20:15:29

    这道題真的是没有时间写数据了,如果你有兴趣也可以看一看。下面那个程序我没有调试过,反正只是留作纪念吧。
    这道题的思路:先处理环,用tarjan老套路縮环,之后拓扑排序分层。然后用bitset或者每个点维护400个int型(手搞bitset)表示某个点可以由哪一些点到达。之后分两种情况:1:这次询问的两个点在同一个強連通分量上,直接输出编号小的那一个点。2:这次询问的两个店不在同一个强连通分量上,就可以进行二分答案在哪一层。因为越后面层数上的点可以由更多的点到达,所以这个符合二分的单调性。如果在这一层找不到包含它们两个点路径的点,就扩大搜索的规模,否则缩小规模。最后就把答案所在层数以及那一个点二分出来了。
    时间复杂度O(n+n+logn * q)

    #include<bits/stdc++.h>
    inline void read(int&a)
    {
        a=0;char c=getchar();
        while(c<'0'||c>'9')c=getchar();
        while(c>='0'&&c<='9')
        {
            a=(a<<1)+(a<<3)+c-'0';
            c=getchar();
        }
    }
    inline void write(int a)
    {
        if(a<0){a=-a;putchar('-');}
        if(a>9)write(a/10);
        putchar(a%10+'0');
    }
    const int maxn=10001;
    int n,m,d1=0,d=0,q;
    int next1[maxn],to1[maxn],from1[maxn],point1[maxn];
    inline void add1(int a,int b)
    {
        next1[++d1]=point1[a];
        point1[a]=d1;
        to1[d1]=b;
        from1[d1]=a;
    }
    struct POINT
    {
        int has[400];
        inline bool son(int x)
        {
            int k=(x-1)/30,t=(x-1)%30;
            if(has[k]&(1<<t-1))return true;
            return false;
        }
        inline void merge(const POINT&a)
        {
            for(int i=1;i<=n/30+1;i++)
                has[i]=a.has[i]|has[i];
        }
    }have[maxn];
    int tt=0;
    int belong[maxn],stack[maxn],dfn[maxn],end=0;
    bool in_stack[maxn],vis[maxn];
    void tarjan(int p)
    {
        vis[p]=true;
        belong[p]=dfn[p]=++tt;
        int side=point1[p];
        while(side)
        {
            if(!vis[to1[side]])
            {
                in_stack[to1[side]]=true;
                stack[++end]=to1[side];
                tarjan(to1[side]);
                belong[p]=std::min(belong[to1[side]],belong[p]);
            }
            else if(in_stack[to1[side]])
            {
                belong[p]=std::min(belong[to1[side]],belong[p]);
            }
            side=next1[side];
        }
        if(belong[p]==dfn[p])
        {
            while(stack[end]!=p)
            {
                belong[stack[end]]=p;
                in_stack[stack[end]]=false;
                --end;
            }
            belong[p]=p;
            in_stack[p]=false;
            --end;
        }
    }
    int next[maxn],to[maxn],point[maxn],in[maxn];
    inline void add(int a,int b)
    {
        next[++d]=point[a];
        to[d]=b;
        point[a]=d;
        ++in[a];
    }
    void dfs(int p)
    {
        have[p].has[(p-1)%30]&=1<<p-1;
        int side=point[p];
        while(side)
        {
            have[to[side]].merge(have[p]);
            dfs(to[side]);
            side=next[side];
        }
    }
    int start=0,que[maxn];
    int in_step[maxn][maxn],step[maxn],maxstep=0;
    void topo()
    {
        while(end>=start)
        {
            int p=que[start],side=next[side];
            while(side)
            {
                --in[to[side]];
                if(!in[to[side]]){que[++end]=to[side];step[to[side]]=step[p]+1;}
            }
            maxstep=std::max(step[p],maxstep);
            ++start;
        }
    }
    inline int find(int s,int x,int y)
    {
        int ans=INT_MAX;
        for(int i=1;i<=in_step[x][0];++i)
        {
            if(have[in_step[s][i]].son(x)&&have[in_step[s][i]].son(y))
                ans=std::min(ans,in_step[s][i]);
        }
        if(ans==INT_MAX)return 0;
        return ans;
    }
    int lcson(int x,int y)
    {
        if(belong[x]==belong[y])return std::min(x,y);
        x=belong[x],y=belong[y];
        if(!find(maxstep,x,y))return -1;
        int ans,l=std::max(step[x],step[y]),r=maxstep;
        while(l!=r)
        {
            int mid=l+r>>1;
            ans=find(mid,x,y);
            if(!ans)l=mid+1;
            else r=mid;
        }
        return ans;
    }
    int main()
    {
        memset(vis,false,sizeof(vis));
        memset(in_step,0,sizeof(in_step));
        memset(in,0,sizeof(in));
        memset(in_stack,false,sizeof(in_stack));
        memset(point1,0,sizeof(point1));
        read(n);read(m);int u,v;
        for(int i=1;i<=m;i++)
        {
            read(u);read(v);
            add1(u,v);
        }
        for(int i=1;i<=n;i++)
            if(!vis[i])
            {
                in_stack[i]=true;
                stack[++end]=i;
                tarjan(i);
            }
        for(int i=1;i<=d;i++)
            if(belong[from1[i]]!=belong[to1[i]])add(from1[i],to1[i]);
        for(int i=1;i<=n;i++)
            if(!in[i]&&belong[i]==i){que[++end]=i;step[i]=1;}
        end=-1;
        topo();
        read(q);
        int x,y;
        while(q--)
        {
            read(x);read(y);
            write(lcson(x,y));printf("\n");
        }
        return 0;
    }
    
  • 1

信息

难度
10
分类
(无)
标签
(无)
递交数
1
已通过
0
通过率
0%
上传者