zoukankan      html  css  js  c++  java
  • 洛谷2783 有机化学之神偶尔会做作弊

    题目戳这里
    一句话题意

    一个无向图,先缩掉所有的环,再询问两点直接隔了多少个点(两端也算)。

    Solution

    似乎难度称不上黑题,思路也很明显
    直接Tarjan缩点后求LCA,深度之差就是相隔的点数。
    但注意特判LCA=x或y的情况。
    本来早就可以A了,结果居然LCA打错,无语...
    可能难就难在代码比较长,有点绕,但是想清楚还是蛮好打的。
    也没什么好说的,直接看代码吧。

    Coding

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 500005;
    struct road
    {
        int to,next;
    }e[N*10];
    int head[N],cnt,be[N],to[N],num[N];
    void add(int x,int y)
    {
        cnt++;
        e[cnt].to=y;
        e[cnt].next=head[x];
        head[x]=cnt;
    }
    int sum,color[N],low[N],ins[N],tim[N],sta[N],top=1,col;
    void Tarjan(int x,int last)
    {
        tim[x]=low[x]=++sum;
        sta[top++]=x;
        ins[x]=1;
        for(int i=head[x];i!=0;i=e[i].next)
        {
          if(e[i].to!=last)
          {
            if(ins[e[i].to]==0)
            {
                Tarjan(e[i].to,x);
                low[x]=min(low[x],low[e[i].to]);
            }
            else if(ins[e[i].to]==1)
                 	low[x]=min(low[x],tim[e[i].to]);
          }
        }
        if(tim[x]==low[x])
        {
            col++;
            do
            {
                top--;
                color[sta[top]]=col;
                ins[sta[top]]=-1;
            }while(sta[top]!=x);
        }
        return ;
    }
    int n,m,news[N],fa[N],LCA[N][20],dep[N];
    road edge[N*10];
    void Readd(int x,int y)
    {
        cnt++;
        edge[cnt].to=y;
        edge[cnt].next=head[x];
        head[x]=cnt;
    }
    queue<int> q;
    bool lemon[N];
    void dfs(int x,int deep,int last)
    {
        dep[x]=deep; fa[x]=last;
        for(int i=head[x];i;i=edge[i].next)
         if(edge[i].to!=last&&dep[edge[i].to]==0) dfs(edge[i].to,deep+1,x);
    }
    int Lca(int x,int y)
    {
        if(dep[x]<dep[y]) swap(x,y);
        int popx=x,popy=y,last;
        int p=0,qu=dep[x]-dep[y];
        while(qu>0)
        {
            if(qu%2==1) x=LCA[x][p];
            qu/=2;
            p++;
        }
        if(x!=y)
        {
            for(int j=19;j>=0;j--)
              if(LCA[x][j]!=LCA[y][j]) x=LCA[x][j],y=LCA[y][j];
            last=LCA[x][0];
        }
        else last=y;
        if(popy==last) return dep[popx]-dep[last]+1;
        else return dep[popx]-dep[last]+dep[popy]-dep[last]+1;
    }
    void change(int num)
    {
        int ans[20],cl=0;
        if(num==0) {cout<<0<<endl; return ;}
        while(num>0)
        {
            ans[++cl]=num%2;
            num/=2;
        }
        for(int i=cl;i>=1;i--)
            printf("%d",ans[i]);
        cout<<endl;
    }		
    int main()
    {
        cin>>n>>m;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&be[i],&to[i]);
            add(be[i],to[i]);
            add(to[i],be[i]);
        }
        for(int i=1;i<=n;i++)
            if(ins[i]==0) Tarjan(i,i);
        for(int i=1;i<=n;i++)
        	num[color[i]]++;
        memset(head,0,sizeof(head));
        cnt=0;
        for(int i=1;i<=m;i++)
            if(color[be[i]]!=color[to[i]]||(color[be[i]]==color[to[i]]&&num[color[be[i]]]==2))
            {
                Readd(color[be[i]],color[to[i]]);
                Readd(color[to[i]],color[be[i]]);
            }
        dfs(1,1,1);
        for(int i=1;i<=col;i++)
            LCA[i][0]=fa[i];
        for(int j=1;j<=19;j++)
          for(int i=1;i<=col;i++)
             LCA[i][j]=LCA[LCA[i][j-1]][j-1];
        int T;
        cin>>T;
        for(int i=1;i<=T;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            change(Lca(color[x],color[y]));
        }	
        return 0;
    }
    
  • 相关阅读:
    shell 脚本学习笔记1
    手把手教你uiautomator_android自动化测试第一个示范
    ubuntu设置环境变量
    albert1017 Linux下压缩某个文件夹(文件夹打包)
    /proc/sysrq-trigger详解
    Android攻城狮学习笔记—入门篇二
    Android攻城狮学习笔记—入门篇一
    《移动App测试实战》读书笔记
    Linux-Ubuntu
    Android-应用性能测试
  • 原文地址:https://www.cnblogs.com/Le-mon/p/9622306.html
Copyright © 2011-2022 走看看