【BZOJ】4390 [Usaco2015 dec]Max Flow LCA+树上差分

来源:互联网 发布:仁化县网络问政平台 编辑:程序博客网 时间:2024/05/17 23:13

题目传送门

树上差分是个好东西,“可以让复杂的题目变的简单许多”——来自ZZK。

先切一道比较裸的树上差分,为接下来的“NOIP2015运输计划”做准备。

这题题意非常清楚,给定一棵树,每次给一条路径上所有点权加一,求所有操作后的最大点权。

考虑树上差分,每次在给定的两个点xy上打上+1的标记,在lca(x,y)lca(x,y)的父亲上打上1的标记。

最后遍历一遍整棵树即可得到所有点的点权了。

附上AC代码:

#include <cstdio>#include <cctype>#include <algorithm>using namespace std;const int N=1e5+10;struct side{    int to,nt;}s[N<<1];int n,m,h[N],num,x,y,d[N],f[N],sz[N],hs[N],top[N],t,ans,sum[N];inline char nc(){    static char ch[100010],*p1=ch,*p2=ch;    return p1==p2&&(p2=(p1=ch)+fread(ch,1,100010,stdin),p1==p2)?EOF:*p1++;}inline void read(int &a){    static char c=nc();int f=1;    for (;!isdigit(c);c=nc()) if (c=='-') f=-1;    for (a=0;isdigit(c);a=a*10+c-'0',c=nc());    a*=f;return;}inline void add(int x,int y){    s[++num]=(side){y,h[x]},h[x]=num;    s[++num]=(side){x,h[y]},h[y]=num;}inline void so1(int x,int fa){    d[x]=d[f[x]=fa]+1,sz[x]=1;    for (int i=h[x]; i; i=s[i].nt)        if (s[i].to!=fa){            so1(s[i].to,x),sz[x]+=sz[s[i].to];            if (sz[s[i].to]>sz[hs[x]]) hs[x]=s[i].to;        }    return;}inline void so2(int x,int fa){    top[x]=fa;    if (hs[x]) so2(hs[x],fa);    for (int i=h[x]; i; i=s[i].nt)        if (s[i].to!=f[x]&&s[i].to!=hs[x]) so2(s[i].to,s[i].to);    return;}inline int query(int x,int y){    for (int fx=top[x],fy=top[y]; fx!=fy; x=f[fx],fx=top[x])        if (d[fx]<d[fy]) swap(fx,fy),swap(x,y);    return d[x]<d[y]?x:y;}inline void so(int x,int fa){    for (int i=h[x]; i; i=s[i].nt)        if (s[i].to!=fa) so(s[i].to,x),sum[x]+=sum[s[i].to];    return;}int main(void){    read(n),read(m);    for (int i=1; i<n; ++i) read(x),read(y),add(x,y);    so1(1,0),so2(1,1);    while (m--) read(x),read(y),t=query(x,y),++sum[x],++sum[y],--sum[t],--sum[f[t]];    so(1,0);    for (int i=1; i<=n; ++i) ans=max(ans,sum[i]);    return printf("%d\n",ans),0;}
阅读全文
0 0
原创粉丝点击