P3128 [USACO15DEC]最大流Max Flow-树上点差分-第一弹

5 篇文章 0 订阅
  • P3128 [USACO15DEC]最大流Max Flow
  • 树上差分,顾名思义就是在树上搞差分,点差分:
  • 我们在power[lca(u,v)]-=x,而是把power[lca(u,v)]-=x并把power[dp[lca(u,v)]]-=x。
  • 因为lca(u,v)也在u..v这条路径上,它同样需要被加x。回溯的时候会从u和v两个方向都给lca(u,v)加一个x。
  • 而它只能加一个,因此power[lca(u,v)]-=x。而lca(u,v)的爸爸则根本无法被加,在lca(u,v)已经只加一个x了.
  • 因此power[dp[lca(u,v)]]-=x就能让lca(u,v)的爸爸不加x。
  • #include<bits/stdc++.h>
    using namespace std;
    #define maxn 123456
    int n,head[maxn],deep[maxn],power[maxn];
    int cnt,ans,x,y,k,dp[maxn][50],lcaaaaa;
    struct edg
    {
        int v,to;
    } edge[maxn];
    void adda(int x,int y)
    {
        edge[++cnt].to=head[x];
        edge[cnt].v=y;
        head[x]=cnt;
    }
    void dfs(int cur,int fa)
    {
        deep[cur]=deep[fa]+1;
        dp[cur][0]=fa;
        for(int i=1; (1<<i)<=deep[cur]; i++)
            dp[cur][i]=dp[dp[cur][i-1]][i-1];
        for(int i=head[cur]; i!=-1; i=edge[i].to)
            if(edge[i].v!=fa)
                dfs(edge[i].v,cur);
    }
    int lca(int x,int y)
    {
        if(deep[x]<deep[y])
            swap(x,y);
        for(int i=30; i>=0; i--)
            if(deep[x]-(1<<i)>=deep[y])
                x=dp[x][i];
        if(x==y)return x;
        for(int i=30; i>=0; i--)
            if(dp[x][i]!=dp[y][i])
            {
                x=dp[x][i];
                y=dp[y][i];
            }
        return dp[x][0];
    }
    void get(int cur,int fa)
    {
        for(int i=head[cur]; i!=-1; i=edge[i].to)
        {
            if(edge[i].v==fa)continue;
            get(edge[i].v,cur);
            power[cur]+=power[edge[i].v];
        }
        ans=max(ans,power[cur]);
    }
    int main()
    {
        memset(head,-1,sizeof(head));
        scanf("%d%d",&n,&k);
        for(int i=1; i<n; i++)
        {
            scanf("%d%d",&x,&y);
            adda(x,y);
            adda(y,x);
        }
        deep[0]=0;
        dfs(1,0);
        while(k--)
        {
            scanf("%d%d",&x,&y);
            lcaaaaa=lca(x,y);
            power[x]++;
            power[y]++;
            power[lcaaaaa]--;
            power[dp[lcaaaaa][0]]--;
        }
        get(1,0);
        printf("%d\n",ans);
        return 0;
    }
    

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值