树上差分是个好东西,“可以让复杂的题目变的简单许多”——来自ZZK。
先切一道比较裸的树上差分,为接下来的“NOIP2015运输计划”做准备。
这题题意非常清楚,给定一棵树,每次给一条路径上所有点权加一,求所有操作后的最大点权。
考虑树上差分,每次在给定的两个点
x
和
最后遍历一遍整棵树即可得到所有点的点权了。
附上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;
}