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;
}

 

### Feeding the Cows B 问题解析 在《USACO 2022年12月比赛》的 Silver 组第二题中,题目要求解决一个关于奶牛喂养的问题。具体描述如下: 输入包括一个长度为 $ n $ 的字符串,表示一排奶牛,其中每个字符为 'C' 或 'W',分别表示该位置有一头奶牛或是一片草地。目标是通过最少的操作次数,使得每头奶牛('C')都能在其左侧或右侧至少有一个相邻的草地('W'),以便能够被喂养。每次操作可以将一个 'C' 变成 'W' 或者将一个 'W' 变成 'C'。 输出为最小的操作次数,若无法满足条件则输出 -1。 #### 问题分析 1. **问题条件**: - 每个奶牛必须在其左右至少有一个相邻的草地。 - 每次操作可以修改一个字符('C' <-> 'W')。 - 需要找出最小操作次数。 2. **贪心策略**: - 从左到右遍历字符串,当遇到一个奶牛('C')时,检查其右侧是否有一个草地('W'),如果存在,将该草地变为奶牛的“喂养”。 - 如果右侧没有草地,则需要修改当前奶牛或其右侧的某个字符以满足条件。 3. **实现逻辑**: - 遍历字符串,维护一个指针,标记当前可以使用的草地位置。 - 如果当前字符是 'C',且其右侧没有可用草地,则需要修改一个字符。 - 记录每次操作,并确保最终所有奶牛都能被喂养。 #### 示例代码实现 ```cpp #include <iostream> #include <string> using namespace std; int main() { int n; string s; cin >> n >> s; int operations = 0; int lastGrass = -1; for (int i = 0; i < n; ++i) { if (s[i] == 'C') { if (lastGrass == -1 || lastGrass < i - 1) { // Check if there is a grass to the right bool found = false; for (int j = i + 1; j < n; ++j) { if (s[j] == 'W') { lastGrass = j; found = true; break; } } if (!found) { cout << -1 << endl; return 0; } } lastGrass = i + 1; // Mark the next available grass position continue; } else if (s[i] == 'W') { lastGrass = i; } } cout << operations << endl; return 0; } ``` #### 时间复杂度 - 该算法的时间复杂度为 $ O(n) $,因为每个字符最多被访问两次(一次遍历,一次查找草地)。 #### 空间复杂度 - 空间复杂度为 $ O(1) $,仅使用了常量级的额外空间。 #### 注意事项 - 需要处理边界情况,例如字符串末尾没有草地。 - 如果无法满足条件(即存在无法喂养的奶牛),应输出 -1。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值