zoukankan      html  css  js  c++  java
  • P5676 [GZOI2017]小z玩游戏 Tarjan+优化建图

    题目描述




    分析

    一开始看到这道题,首先想到的就是建好边后跑一个Tarjan缩点,将siz大于1的节点统计一下,输出结果
    Tarjan非常显然易得,关键就是怎么建边
    比较好想的一种思路就是枚举每一个兴奋程度
    对于每一个兴奋程度,再将有趣程度枚举一遍
    如果有趣程度是兴奋程度的倍数的话,在两个节点之间建一条有向边
    我们拿第二个样例模拟一下,建好边后就是下面这样

    那么缩点后大小不为1的强连通分量只有一个,它的大小为3
    那么最终的答案就是(3)
    但是这样的建边效率为(n^2),复杂度接受不了
    所以我们考虑更优秀的建边方法
    这里要用到的是建虚点的方法
    1.建一个由 有趣程度 到 点 的边
    2.建一个由 点 到 兴奋程度 的边
    3.重点:建一个兴奋程度整数倍的边
    要注意的是建虚点的时候,要把游戏的编号加上一个(n)
    避免和原先的编号重复
    然后思路就和(n^2)的解法一样
    至于时间复杂度,根据大佬的证明,是

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=2e6+5;
    struct asd{
        int from,to,next;
    }b[maxn];
    int head[maxn],tot=1;
    void ad(int aa,int bb){
        b[tot].from=aa;
        b[tot].to=bb;
        b[tot].next=head[aa];
        head[aa]=tot++;
    }
    int dfn[maxn],low[maxn],top,sta[maxn],dfnc,shuyu[maxn],siz[maxn],js,vis[maxn];
    void tar(int xx){
        dfn[xx]=low[xx]=++dfnc;
        sta[++top]=xx;
        for(int i=head[xx];i!=-1;i=b[i].next){
            int u=b[i].to;
            if(!dfn[u]){
                tar(u);
                low[xx]=min(low[xx],low[u]);
            } else if(!shuyu[u]){
                low[xx]=min(low[xx],dfn[u]);
            }
        }
        if(low[xx]==dfn[xx]){
            js++;
            siz[js]=1;
            while(sta[top]!=xx){
                int now=sta[top--];
                shuyu[now]=js;
                siz[js]++;
                vis[now]=1;
            }
            top--;
            shuyu[xx]=js;
            if(siz[js]>1) vis[xx]=1;
        }
    }
    int main(){
        int t;
        scanf("%d",&t);
        while(t--){
            memset(head,-1,sizeof(head));
            memset(&b,0,sizeof(struct asd));
            memset(dfn,0,sizeof(dfn));
            memset(low,0,sizeof(low));
            tot=1,js=0,dfnc=0,top=0;
            memset(vis,0,sizeof(vis));
            memset(sta,0,sizeof(sta));
            memset(shuyu,0,sizeof(shuyu));
            memset(siz,0,sizeof(siz));
            int n;
            scanf("%d",&n);
            int mmax=0;
            for(int i=1;i<=n;i++){
                int aa;
                scanf("%d",&aa);
                ad(n+aa,i);
                mmax=max(mmax,aa);
            }
            for(int i=1;i<=n;i++){
                int aa;
                scanf("%d",&aa);
                ad(i,n+aa);
            }
            for(int i=1;i<=mmax;i++){
                for(int j=2;j*i<=mmax;j++){
                    ad(n+i,n+i*j);
                }
            }
            for(int i=1;i<=n;i++){
                if(!dfn[i]) tar(i);
            }
            int ans=0;
            for(int i=1;i<=n;i++){
                if(vis[i]==1) ans++;
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    在aarch版编译libEasyRTSPClient库无法通过问题解决
    视频流媒体推流平台RTMP协议是如何进行网络连接并推送视频流的?
    建立视频直播服务用RTMP协议还是RTSP协议?
    如何搭建RTMP视频流媒体推流服务器
    Winsock Select模型范例
    欢迎大家加入broncho社区与broncho共同发展
    在Windows环境使用Broncho映像[转]
    DirectFB几个辅助工具
    Linux手机研发要过五大难关
    让语言选择即时生效
  • 原文地址:https://www.cnblogs.com/liuchanglc/p/13199547.html
Copyright © 2011-2022 走看看