poj 3417 Network LCA+树形dp

题目链接

http://poj.org/problem?id=3417

题意

某人要攻击一个网络,网络是由n-1条边和n个点组成的连通图,网络管理员知道网络很脆弱,一旦某条断掉,将会使整个网络不连通,所以他想多加m条边。攻击网络的人想攻击一条在加边前的图中的边,和一条新加的边,试求出有多少种方式,能够达到目的。

思路

原图是树,画图可以发现,某两个点u和v加上一条边,会形成u-lca(u,v)-v-u 的环,这时去掉新加的边和原图中的一条边即能达到目的,如果某条边在两个或两个以上的环中,那么删除他不能达到目的,如果某条边仍然是树边(没形成环),那么删除它即会使图不连通,这时再删除新加的任意一条都能达到目的,对答案的贡献是m。
用dp[u]表示u与其父亲结点之间的边在几个环中,需要注意的是dp数组的初始化。然后在树上dp。
最后:
如果除了根结点的任意结点u:
dp[u] == 0 对答案贡献m
dp[u] == 1 对答案贡献1
其他对答案没有贡献
这题卡vector=_=

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
using namespace std;
const int INF = ( 2e9 ) + 2;
const ll maxn = 1e5+10;
const int maxm = 2e5+10;
//vector g[maxn];
int dp[maxn];
bool vis[maxn];
struct edge
{
    int v,lca,next;
}e[maxm],e2[maxm];
int head[maxn],head2[maxn],f[maxn];
int tot,tot2;
void add(int u,int v)
{
    e[tot].v=v;
    e[tot].next=head[u];
    head[u]=tot++;
}
void add2(int u,int v)
{
    e2[tot2].v=v;
    e2[tot2].next=head2[u];
    head2[u]=tot2++;
}
void init(int n)
{
    memset(head,-1,sizeof(head));
    memset(head2,-1,sizeof(head2));
    memset(vis,0,sizeof(vis));
    memset(dp,0,sizeof(dp));
    tot=tot2=0;
//  for(int i=1;i<=n;i++)
//  g[i].clear();
}
int Find(int x)
{
    return f[x]==x?x:f[x]=Find(f[x]);
}
void dfs(int u)
{
    f[u]=u;
    vis[u]=1;
    for(int i=head[u];i!=-1;i=e[i].next)
    {
        int v=e[i].v;
        if(vis[v])
        e[i].lca=e[i^1].lca=Find(v);
    }
    for(int i=head2[u];i!=-1;i=e2[i].next)
    {
        int v=e2[i].v;
        if(!vis[v])
        {
            dfs(v);
            f[v]=u;
        }
    }
}
void dfs2(int u,int fa)
{
    for(int i=head2[u];i!=-1;i=e2[i].next)
    {
        int v=e2[i].v;
        if(v!=fa)
        {
            dfs2(v,u);
            dp[u]+=dp[v];
        }
    }
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        int u,v;
        init(n);
        for(int i=0;i1;i++)
        {
            scanf("%d%d",&u,&v);
            add2(u,v);
            add2(v,u);
        }
        int ans=0;
        for(int i=0;iscanf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
            dp[u]++;dp[v]++;
        }
        dfs(1);
        for(int i=0;i2)
        dp[e[i].lca]-=2;

        dfs2(1,-1);
        for(int i=2;i<=n;i++)
        if(dp[i]==0)ans+=m;
        else if(dp[i]==1)ans+=1;
        printf("%d\n",ans);
    }
}

你可能感兴趣的:(——图论——,LCA)