USACO 2015 Dec Gold 最大流

Description

给定一棵有N个点的树,所有节点的权值都为0。
有K次操作,每次指定两个点s,t,将s到t路径上所有点的权值都加一。
请输出K次操作完毕后权值最大的那个点的权值。

Input

第一行,两个整数N(2≤N≤50,000)和K(1≤K≤100,000)。 
接下来N-1行,每行两个整数a和b,表示a和b有边(x≠y)。 
接下来K行,每行两个整数s和t,表示一个操作的起止点。

Output

一个数表示最大权值点的权值。

Sample Input

5 10

3 4

1 5

4 2

5 4

5 4

5 4

3 5

4 3

4 3

1 3

3 5

5 4

1 5

3 4

Sample Output

9

树剖裸题。

//re去结构体和inline 
#include<bits/stdc++.h>
using namespace std;
inline int get(){register int re=0,f=1;register char c;while(c=getchar(),(c>='0'&&c<='9')^1)f=c^'-';while(re=(re<<1)+(re<<3)+(c^48),c=getchar(),(c>='0'&&c<='9'));return f?re:-re;}
const int N = 5e4+10;
#define FOR(i,L,R) for(register int i=(L);i<=(R);++i)
int n,m,cnt;
struct Graph{
	int c[N];
	vector<int>G[N];
	inline void init(){
		scanf("%d%d",&n,&m);
		FOR(i,1,n-1){
			int x,y;scanf("%d%d",&x,&y);
			G[x].push_back(y);
			G[y].push_back(x);
		}
	}
	#define to G[x][i]
	int p[N],siz[N],son[N],dep[N];
	inline int dfs1(int x,int fa,int depth){
		siz[x]=1;
		int sz=G[x].size()-1;
		FOR(i,0,sz)if(to^fa){
			siz[x]+=dfs1(to,p[to]=x,dep[to]=depth+1);
			if(siz[son[x]]<siz[to])son[x]=to;
		}return siz[x];
	}
	int rp[N],top[N];
	inline void dfs2(int x,int sp){
		rp[x]=++cnt;
		top[x]=sp;
		if(son[x])dfs2(son[x],sp);
		int sz=G[x].size()-1;
		FOR(i,0,sz)if(to^p[x]&&to^son[x])dfs2(to,to);
	}
}g;
struct Seg{
	struct tree{
		int l,r,k,add;
	}a[N*40];
	#define ls v<<1
	#define rs v<<1|1
	void pushdn(int v){
		if(a[v].add){
			int k=a[v].add;
			a[ls].add+=k,a[ls].k+=k;
			a[rs].add+=k,a[rs].k+=k;
			a[v].add=0;
		}
	}
	void pushup(int v){
		a[v].k=max(a[ls].k,a[rs].k);
	}
	void Addk(int v,int A,int B){
		if(a[v].l>B||a[v].r<A)return ;
		if(A<=a[v].l&&a[v].r<=B)return ++a[v].k,++a[v].add,void();
		pushdn(v);
		Addk(ls,A,B),Addk(rs,A,B);
		pushup(v);
	}
	void build(int v,int l,int r){
		a[v]=((tree){l,r,0,0});
		if(l==r)return ;
		int mid=l+r>>1;
		build(ls,l,mid),build(rs,mid+1,r);
	}
}t;
#define top(a) g.top[a]
#define dep(a) g.dep[a]
#define fa(a) g.p[a]
void Change(int x,int y){
	int t1=top(x),t2=top(y);
	while(t1^t2){
		if(dep(t1)<dep(t2))swap(x,y),swap(t1,t2);
		t.Addk(1,g.rp[t1],g.rp[x]);
		x=fa(t1);t1=top(x);
	}if(dep(x)>dep(y))swap(x,y);
	t.Addk(1,g.rp[x],g.rp[y]);
}
int main(){
	g.init();
	g.dfs1(1,g.p[1]=0,g.dep[1]=1);
	g.dfs2(1,1);
	t.build(1,1,cnt);
	FOR(i,1,m){
		int x,y;scanf("%d%d",&x,&y);
		Change(x,y);
	}cout<<t.a[1].k<<"\n";
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值