zoukankan      html  css  js  c++  java
  • 【SHOI2006】仙人掌

    题目链接

    分析:

      无向仙人掌比较简单。

      一个仙人掌首先是个连通图。一遍深搜可以筛掉。

      根据定义,如果有任意边被不同的简单环经过,它不是仙人掌。

      那么我们现在要对边,计数经过它的环。

      这里的做法是树上差分。第一遍深搜还要搞出$DFS$树和倍增数组,遇到非树边记录下来。

      $Trickquad vis$数组设三个状态:出边到达$0$点,这条边作为树边,到达的点改成$1$点;到达$1$点,记录成环,自己变成$2$点;到达$2$点,这条成环边已经被记录过,不用管。

      用每个点表示它的“到父边”上的计数,就是在每条成环边的端点上$++$,它们的$LCA$上$-=2$,最后再来一遍深搜或者借助$DFN$序由下往上传标记即可。

      这样得到的边上的计数不代表实际有多少个简单环经过它。但一旦出现共边的简单环,一定有边上的计数超过$1$。这就够了。

      接下来计算“仙人数”。

      既然不能破坏连通性,那么不能剪那些不在简单环上的树边。发现去掉任意简单环上的一条边满足条件。于是答案就很显然了。设有$k$个简单环,第$i$个简单环有$s_i$条边,那么$$ans=prodlimits_{i=1}^{k}(s_i+1)$$

      用$LCA$算$s$值,加上高精度,没了。

    实现(100分):

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<map>
    #include<set>
    #define IL inline
    #define RG register
    #define _1 first
    #define _2 second
    using namespace std;
    typedef long long LL;
    const int N=2e4;
    const int M=1e6;
    const int L=15;
    
    struct Edge{
        int to,nxt;
        Edge(){}
        Edge(int p1,int p2):to(p1),nxt(p2){}
    }e[M*2+3];
        int etop,h[N+3];
        
    IL void adde(int u,int v){
        e[++etop]=Edge(v,h[u]);    h[u]=etop;
        e[++etop]=Edge(u,h[v]);    h[v]=etop;
        
    }
    
        int n,m;
        int dep[N+3],fa[N+3][L+3];
        int cnt,mdep,mlog;
        int vis[N+3];
        int k,v1[M+3],v2[M+3];
    
    void dfs(int u,int fr){
        for(int i=h[u];~i;i=e[i].nxt){
            int v=e[i].to;
            if(v==fr)
                continue;
            if(vis[v]==1){
                k++;
                v1[k]=u;
                v2[k]=v;
                vis[u]=2;
                
            }
            if(vis[v]>0)
                continue;
                
            vis[v]=1;
            dep[v]=dep[u]+1;
            mdep=max(mdep,dep[v]);
            fa[v][0]=u;
            cnt++;
            dfs(v,u);
            
        }
        
    }
    
    IL void swap(int &x,int &y){
        int t=x;    x=y;    y=t;
    }
    
    IL int lca(int x,int y){
        if(dep[x]<dep[y])
            swap(x,y);
        
        for(int l=mlog;l>=0;l--)
        if(dep[fa[x][l]]>=dep[y])
            x=fa[x][l];
            
        if(x==y)
            return x;
        
        for(int l=mlog;l>=0;l--)
        if(fa[x][l]!=fa[y][l]){
            x=fa[x][l];    y=fa[y][l];
        }
        
        return fa[x][0];
        
    }
    
        int mrk[N+3];
        
    void dfs2(int u){
        for(int i=h[u];~i;i=e[i].nxt){
            int v=e[i].to;
            if(vis[v])
                continue;
                
            vis[v]=true;
            dfs2(v);
            mrk[u]+=mrk[v];
            
        }
        
    }
    
    const int Len=3180;
    const LL wgt=1e8;
    
    struct Num{
        int l;
        LL a[Len+3];
        
        Num(){
            l=1;    memset(a,0,sizeof a);
        }
        Num(LL x){
            l=0;    memset(a,0,sizeof a);
            while(x>0){
                a[++l]=x%wgt;
                x/=wgt;
                
            }
            
        }
        
        IL LL operator[](int i){
            return a[i];
        }
        
    };
    
    IL Num operator+(Num x,Num y){
        Num z;    z.l=max(x.l,y.l);
        for(int i=1;i<=z.l;i++){
            z.a[i]+=x[i]+y[i];
            z.a[i+1]+=z[i]/wgt;
            z.a[i]%=wgt;
            
        }
        if(z[z.l+1]>0)
            z.l++;
        return z;
        
    }
    
    IL Num operator*(Num x,Num y){
        Num z;    z.l=x.l+y.l+2;
        for(int i=1;i<=x.l;i++)
            for(int j=1;j<=y.l;j++)
                z.a[i+j-1]+=x[i]*y[j];
        for(int i=1;i<=x.l;i++)
        if(z[i]>=wgt){
            z.a[i+1]+=z[i]/wgt;
            z.a[i]%=wgt;
            
        }
        while(z[z.l]==0)
            z.l--;
        return z;
        
    }
    
    IL Num operator*=(Num &x,Num y){
        return x=x*y;
    }
    
    IL void write(Num x){
        printf("%lld",x[x.l]);
        for(int i=x.l-1;i>=1;i--)
            printf("%08lld",x[i]);
    }
    
    int main(){
        scanf("%d%d",&n,&m);
        etop=-1;
        memset(h,-1,sizeof h);
        for(int i=0;i<m;i++){
            int k,p,v;    scanf("%d%d",&k,&p);
            for(int j=1;j<k;j++){
                scanf("%d",&v);
                adde(p,v);
                p=v;
                
            }
            
        }
        
        dep[1]=1;    fa[1][0]=fa[0][0]=dep[0]=0;    
        mdep=0;
        memset(vis,0,sizeof vis);
        vis[1]=true;    cnt=1;
        dfs(1,0);
        
        if(cnt<n){
            printf("0");
            return 0;
            
        }
        
        for(mlog=0;mdep>0;mdep>>=1)
            mlog++;
        for(int l=1;l<=mlog;l++)
            for(int i=1;i<=n;i++)
                fa[i][l]=fa[fa[i][l-1]][l-1];
        
        memset(mrk,0,sizeof mrk);
        for(int i=1;i<=k;i++){
            int x=v1[i],y=v2[i];
            int z=lca(x,y);
            
            if(x==z){
                mrk[y]++;    mrk[x]--;
            }
            else 
            if(y==z){
                mrk[x]++;    mrk[y]--;
            }
            else {
                mrk[x]++;    mrk[y]++;
                mrk[z]-=2;
            }
            
        }
        
        memset(vis,0,sizeof vis);
        vis[1]=true;
        dfs2(1);
        
        for(int i=1;i<=n;i++)
        if(mrk[i]>1){
            printf("0");
            return 0;
            
        }
        
        Num ans(1);
        for(int i=1;i<=k;i++){
            int x=v1[i],y=v2[i];
            int z=lca(x,y);
            
            
            if(x==z)
                ans*=Num(1LL*dep[y]-dep[z]+2);
            else 
            if(y==z)
                ans*=Num(1LL*dep[x]-dep[z]+2);
            else 
                ans*=Num(1LL*dep[x]+dep[y]-2*dep[z]+2);
            
        }
        
        write(ans);
    
        return 0;
    
    }
    View Code

    小结:

      记得讨论范围,没开$long;long$和没上高精然后$WA$掉一样难受。

      树上边计数:树上差分。

  • 相关阅读:
    SSH Secure File Transfer上传文件错误:encountered 1 errors during the transfer解决办法
    出现Unrecognized field "state" (class com.jt.manage.pojo.ItemCat)异常
    (error) DENIED Redis is running in protected mode because protected mode is enabled
    错误:在maven install是抛出 “1.5不支持diamond运算符,请使用source 7或更高版本以启用diamond运算符”
    Java实现POI读取Excel文件,兼容后缀名xls和xlsx
    数据库的主从复制常用Xshell命令
    Linux搭建主从数据库服务器(主从复制)
    项目数据库备份
    Entity Frameword 查询 sql func linq 对比
    jq 选择器基础及拓展
  • 原文地址:https://www.cnblogs.com/Hansue/p/12168186.html
Copyright © 2011-2022 走看看