luoguP3128 [USACO15DEC]最大流Max Flow 题解(树上差分)

链接一下题目:luoguP3128 [USACO15DEC]最大流Max Flow(树上差分板子题)

如果没有学过树上差分,抠这里(其实很简单的,真的):树上差分总结

学了树上差分,这道题就极其显然了,不就是把每一条运输路线差分进去,那就是板子了啊.

树上差分还是很有用的,比较容易写,这种询问很少的题目去敲那么长(还容易出玄学错误)的树剖很浪费,用树上差分就很快了!(//...微笑...\\)

上一波代码:

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<iomanip>
#include<ctime>
#include<queue>
#include<stack>
#define rg register
#define lst long long
#define N 50050
using namespace std;

int n,K,cnt,ans;
struct EDGE{
    int to,nxt;
}edge[N<<1];
int head[N];
int fa[N],v[N],deep[N];
int f[N][25];

inline int read()
{
    rg int s=0,m=1;rg char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')m=-1,ch=getchar();
    while(ch>='0'&&ch<='9')s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
    return s*m;
}

inline void add(rg int p,rg int q)
{
    edge[++cnt]=(EDGE){q,head[p]};
    head[p]=cnt;
}

void dfs(rg int now,rg int fm,rg int dep)//点,父亲,深度
{
    fa[now]=fm;deep[now]=dep;
    f[now][0]=fa[now];
    for(rg int i=1;i<=20;++i)
        f[now][i]=f[f[now][i-1]][i-1];
    for(rg int i=head[now];i;i=edge[i].nxt)
    {
        rg int qw=edge[i].to;
        if(qw!=fm)
            dfs(qw,now,dep+1);
    }
}

inline int lca(rg int p,rg int q)
{
    if(deep[p]<deep[q])swap(p,q);
    while(deep[p]>deep[q])
        for(rg int i=20;i>=0;--i)
            if(deep[f[p][i]]>=deep[q])
                p=f[p][i];
    while(p!=q)
    {
        for(rg int i=20;i>=0;--i)
            if(f[p][i]!=f[q][i])
                p=f[p][i],q=f[q][i];
        if(fa[p]==fa[q])
            p=q=fa[p];
    }
    if(p==q)return p;
}

inline void Insert(rg int p,rg int q)//如模板,差分
{
    v[p]++,v[q]++;//自己++
      rg int LCA=lca(p,q);
//    printf("lca(%d,%d)=%d\n",p,q,LCA);
      v[LCA]--,v[fa[LCA]]--;//LCA和fa[LCA]--
}

void sum(rg int now)
{
    for(rg int i=head[now];i;i=edge[i].nxt)
    {
        rg int qw=edge[i].to;
        if(qw!=fa[now])
        {
            sum(qw);
            v[now]+=v[qw];
        }
    }
    ans=max(ans,v[now]);
}

int main()
{
    n=read(),K=read();
    for(rg int i=1;i<n;++i)
    {
        rg int p=read(),q=read();
        add(p,q),add(q,p);
    }
      dfs(1,0,1);//倍增的预处理
//    for(rg int i=\1;i<=n;++i)cout<<deep[i]<<" ";cout<<endl;
/*    for(rg int i=1;i<=n;++i)
    {
        for(rg int j=0;j<=2;j++)
        {
            printf("f[%d][%d]=%d ",i,j,f[i][j]);
        }
        cout<<endl;
    }
    cout<<endl;*/
    for(rg int i=1;i<=K;++i)
    {
        rg int p=read(),q=read();
          Insert(p,q);//差分
    }
    add(0,1);//0上面也会有标记,所以上面的东西也要弄掉
    sum(0);//dfs遍历顺便找答案
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2018-04-06 16:22  Eternal风度  阅读(413)  评论(1编辑  收藏  举报
/*自定义地址栏logo*/