HDU 5452 Minimum Cut(树链剖分+树差分)

题意:给你一颗生成树,然后有一些额外的边连接在生成树上的两点,问你最少要割几条边才能使图不连通,割的边中只能有一条生成树上的边,不能少也不能多

思路:训练没出,现在来补坑。我们稍加思考可以想到对于一颗生成树,我们其余的边相当于覆盖u,v之前的路线,如果你要割u,v之间的生成树的边的话就要多割一条,我们很直接的想到用线段树来维护区间操作,但是这个题在我们训练的时候是会超时的,所以我们改用树差分,因为我们是树链剖分的,树链剖分有一条性质就是我们在剖分的时候重链的编号是连续的,就是这一条性质保证了可以树差分。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

const int maxn=500008;

int a[maxn],sz[maxn],dep[maxn],fa[maxn],top[maxn],son[maxn],head[maxn];
int w[maxn],num,cnt;
int c[maxn];
struct Edge
{
    int to,next;
};
Edge v[maxn*2];
void init()
{
    num=0;cnt=0;
    memset(head,-1,sizeof(head));
}
void addedge(int x,int y)
{
    v[cnt].to = y;
    v[cnt].next = head[x];
    head[x] = cnt++;
}
void dfs1(int u, int f, int d) {
    dep[u]=d;sz[u]=1;
    son[u]=0;fa[u]=f;
    for(int i=head[u];i!=-1;i = v[i].next){
        int to = v[i].to;
        if(to!=f){
            dfs1(to,u,d+1);
            sz[u]+=sz[to];
            if(sz[son[u]]<sz[to])son[u]=to;
        }
    }
}
void dfs2(int u, int tp) {
    top[u]=tp;
    w[u]=++num;
    if(son[u])dfs2(son[u],tp);
    for(int i = head[u];i!=-1;i=v[i].next){
        int to=v[i].to;
        if(to==fa[u]||to==son[u])continue;
        dfs2(to,to);
    }
}
void modify(int x,int y)
{
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        c[w[top[x]]]++;
        c[w[x]+1]--;
        x=fa[top[x]];
    }
    if(x==y)return ;
    if(dep[x]>dep[y])swap(x,y);
    c[w[son[x]]]++;c[w[y]+1]--;
    return ;
}
int main()
{
    int t,n,m,cas=0;
    scanf("%d",&t);
    while(t--){
        init();
        scanf("%d%d",&n,&m);
        int a,b;
        for(int i=1;i<=n-1;i++){
            scanf("%d%d",&a,&b);
            addedge(a,b);
            addedge(b,a);
        }
        dfs1(1,0,1);
        dfs2(1,1);
        memset(c,0,sizeof(c));
        for(int i=1;i<=m-n+1;i++){
            scanf("%d%d",&a,&b);
            modify(a,b);
        }
        for(int i=1;i<=n;i++){
            c[i]+=c[i-1];
        }
        int ans=0x3f3f3f3f;
        for(int i=1;i<=n;i++){
            if(c[i]!=0&&c[i]){
                ans=min(ans,c[i]);
            }
        }
        printf("Case #%d: %d
",++cas,ans+1);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/lalalatianlalu/p/9756949.html