poj 3417 Network (LCA,路径上有值)

题意:

N个点,构成一棵树。给出这棵树的结构。

M条边,(a1,b1)...(am,bm),代表给树的这些点对连上边。这样就形成了有很多环的一个新”树“。

现在要求你在原树中断一条边,在M条边中断一条边,使得新”树“被分成两个部分。

问有多少种方案。

 

思路:

连上某条新边(a,b),则必定形成一个环。环的路径是a->...->lca(a,b)->...->b,给这些边的值都加1 。

分情况:

在原树中,若一条边的值>=2,去掉这条边,再去掉M条边中的一条,不影响原树的连通性。方案数为0。

       若一条边的值==1,去掉这条边,必须去掉这条边所在环的那条新边(M条边之一)。方案数为1。

     若一条边的值==0,去掉这条边,再随意去掉M条边中的一条,都会破坏原树的连通性。方案数为M。

在计算边的值时,采用DP的方式,若要将路径a->...->lca(a,b)->...->b上的边值都加1,则dp[a]++,dp[b]++,dp[lca(a,b)]-=2。

直接看代码。

 

代码:

int const maxn = 100005;

struct node{
    int to,next,lca;
};

int fa[maxn];
bool vis[maxn];
int head[2*maxn];
int qhead[2*maxn];

node edge[maxn*2];
node qedge[maxn*2];

int n,m,cnt1,cnt2,cn;
int dp[maxn], edgeCount[maxn];


inline void Addedge(int u,int v){
    edge[++cnt1].to=v;
    edge[cnt1].next=head[u];
    head[u]=cnt1;

    edge[++cnt1].to=u;
    edge[cnt1].next=head[v];
    head[v]=cnt1;
}
inline void Addqedge(int u,int v){
    qedge[++cnt2].to=v;
    qedge[cnt2].next=qhead[u];
    qhead[u]=cnt2;

    qedge[++cnt2].to=u;
    qedge[cnt2].next=qhead[v];
    qhead[v]=cnt2;
}
void init(){
    mem(head,-1);  mem(qhead,-1);  mem(vis,false);
    rep(i,1,n) fa[i]=i;
    cnt1=cnt2=0;
}
int findFa(int x){
    return fa[x]==x?x:fa[x]=findFa(fa[x]);
}
void Tarjan_LCA(int u){
    fa[u]=u;
    vis[u]=true;
    for(int i=head[u];i!=-1;i=edge[i].next){
        if(!vis[edge[i].to]){
            Tarjan_LCA(edge[i].to);
            fa[edge[i].to]=u;
        }
    }

    for(int i=qhead[u];i!=-1;i=qedge[i].next){
        if(vis[qedge[i].to])
            qedge[i].lca=findFa(qedge[i].to);
    }
}
int dfsDp(int u,int fa){
    for(int i=head[u];i!=-1;i=edge[i].next){
        int v=edge[i].to;  if(v==fa) continue;
        int t1=dfsDp(v,u);
        edgeCount[++cn]=t1;
        dp[u]+=t1;
    }
    return dp[u];
}


int a,b;
int main(){
    while(scanf("%d%d",&n,&m)!=EOF){
        init();
        rep(i,1,n-1){
            scanf("%d%d",&a,&b);
            Addedge(a,b);
        }
        mem(dp,0);
        rep(i,1,m){
            scanf("%d%d",&a,&b);
            Addqedge(a,b);
            dp[a]++;  dp[b]++;
        }
        Tarjan_LCA(1);
        for(int i=1;i<=cnt2;i+=2){
            dp[qedge[i].lca]-=2;
        }
        mem(edgeCount,0);
        cn=0;
        dfsDp(1,-1);
        int ans=0;
        rep(i,1,cn){
            if(edgeCount[i]==1)
                ans++;
            else if(edgeCount[i]==0)
                ans+=m;
        }
        printf("%d\n",ans);
    }
}

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。