P3128 [USACO15DEC]最大流Max Flow (樹上差分)

傳送門

倍增求LCA+樹上差分

典型的樹上差分題,根據書上差分的思想,w[u]和w[v]分別加1,它們的最近公共祖先(LCA)和LCA的父親各減1,最後dfs求和。

#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
#define mems(a,b) memset(a,b,sizeof(a))

using namespace std;
const int N=5e4+30;

int head[N],d[N],pa[N][25],dis[N],cnt[N];
int tot;
struct node{
    int v,next;
}s[N*2];
void add(int u,int v)
{
    s[tot].v=v;
    s[tot].next=head[u];
    head[u]=tot++;
}
void init()
{
    tot=0;
    mems(head,-1);
    mems(d,0);
    mems(dis,0);
    mems(pa,0);
}
void dfs1(int u,int fa,int len)
{
    d[u]=d[fa]+1;//深度
    dis[u]=len;//到根節點距離
    pa[u][0]=fa;
    for(int i=1;(1<<i)<=d[u];i++)
    {
        pa[u][i]=pa[pa[u][i-1]][i-1];
    }
    for(int i=head[u];~i;i=s[i].next)
    {
        int v=s[i].v;
        if(v!=fa)
            dfs1(v,u,len+1);
    }
}
int lca(int a,int b)
{
    if(d[a]>d[b])
        swap(a,b);
    for(int i=20;i>=0;i--)
    {
        if(d[a]<=d[b]-(1<<i))
            b=pa[b][i];
    }
    if(a==b)
    {
        return a;
    }
    for(int i=20;i>=0;i--)
    {
        if(pa[a][i]==pa[b][i])
            continue;
        else
        {
            a=pa[a][i];
            b=pa[b][i];
        }
    }
    return pa[a][0];
}
void dfs2(int u,int fa)
{
    for(int i=head[u];~i;i=s[i].next)
    {
        int v=s[i].v;
        if(v==fa)
            continue;
        dfs2(v,u);
        cnt[u]+=cnt[v];
    }
}
int main()
{
    int n,k;
    init();
    scanf("%d%d",&n,&k);
    for(int i=1;i<n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v);
        add(v,u);
    }
    dfs1(1,0,0);
    for(int i=0;i<k;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        int c=lca(u,v);
        cnt[u]++,cnt[v]++;
        cnt[c]--;cnt[pa[c][0]]--;
    }
    dfs2(1,0);
    int ans=0;
    for(int i=1;i<=n;i++)
        ans=max(ans,cnt[i]);
    printf("%d\n",ans);
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章