1. 程式人生 > 實用技巧 >[NOIp2015][二分][LCA] 運輸計劃

[NOIp2015][二分][LCA] 運輸計劃

題面

// 二分一個路徑長,並要求所有長度大於該
// 長度的路徑經過同一條邊,且該邊的長度
// 比每條路徑的長度與二分路徑長度差值大,
// 即為所求答案。

// 差分陣列用於確定是否每條路徑都經過該邊

# include <iostream>
# include <cstdio>
# include <cstring>
# define MAXN 300005

struct Edge{
	int v, w, next;
}e[MAXN<<1];
struct Query{
	int x, y;
	int lca, dis;
}q[MAXN];
struct node{
	int fa, hSon, dep, top, siz, dis;
}nd[MAXN];
int hd[MAXN], cntE, d[MAXN], co[MAXN]; // d 是差分陣列
int n, m;int seg[MAXN], cntS;
int L, R;

template<typename T>
void rd(T & x);
void AddE(int u, int v, int w);
void PreDFS(int now, int fa);
void SegDFS(int now, int top);
int  GetLCA(int x, int y);
bool chk(int val);

int main(){
	rd<int>(n), rd<int>(m);

	for(int i = 1, u, v, w; i <= n-1; i++){
		rd<int>(u), rd<int>(v), rd<int>(w);
		AddE(u, v, w); AddE(v, u, w);
		L = std::max(L, w);
	}

	PreDFS(1, 0);
	SegDFS(1, 1);

	for(int i = 1; i <= m; i++){
		rd<int>(q[i].x), rd<int>(q[i].y);
		q[i].lca = GetLCA(q[i].x, q[i].y);
		q[i].dis = nd[q[i].x].dis + nd[q[i].y].dis - (nd[q[i].lca].dis*2);
		R = std::max(R, q[i].dis);
	}

	int l = R-L, r = R+1;
	while(l < r){
		int mid = (l + r) >> 1;
		if(chk(mid)){
			r = mid;
		}
		else{
			l = mid+1;
		}
	}

	printf("%d", l);

	return 0;
}

bool chk(int val){
	memset(d, 0, sizeof(d));
	
	int cntSu = 0;
	for(int i = 1; i <= m; i++){
		if(q[i].dis > val){
			d[q[i].x]++, d[q[i].y]++, d[q[i].lca] -= 2;
			cntSu++;
		}
	}

	for(int i = n; i >= 1; i--){
		d[nd[seg[i]].fa] += d[seg[i]];
		if(co[seg[i]] >= R - val && d[seg[i]] == cntSu){
			return 1;
		}
	}

	return 0;
}

int  GetLCA(int x, int y){
	while(nd[x].top != nd[y].top){
		if(nd[nd[x].top].dep < nd[nd[y].top].dep){
			std::swap(x, y);
		}
		x = nd[nd[x].top].fa;
	}
	return nd[x].dep < nd[y].dep ? x : y;
}

void SegDFS(int now, int top){
	nd[now].top = top;

	if(!nd[now].hSon){
		return;
	}

	SegDFS(nd[now].hSon, top);

	for(int i = hd[now]; i; i = e[i].next){
		if(e[i].v == nd[now].fa || e[i].v == nd[now].hSon){
			continue;
		}

		SegDFS(e[i].v, e[i].v);
	}
}

void PreDFS(int now, int fa){
	nd[now].fa = fa, nd[now].dep = nd[fa].dep + 1;
	nd[now].siz = 1; seg[++cntS] = now;

	for(int i = hd[now]; i; i = e[i].next){
		if(e[i].v == fa){
			continue;
		}

		co[e[i].v] = e[i].w;
		nd[e[i].v].dis = nd[now].dis + e[i].w; // 注意這句話的位置

		PreDFS(e[i].v, now);

		nd[now].siz += nd[e[i].v].siz;
		
		if(nd[e[i].v].siz > nd[nd[now].hSon].siz){
			nd[now].hSon = e[i].v;
		}
	}
}

void AddE(int u, int v, int w){
	e[++cntE].v = v, e[cntE].next = hd[u], hd[u] = cntE;
	e[cntE].w = w;
}

template<typename T>
void rd(T & x){
	x = 0; T fl = 1;
	int ch = getchar();
	for(	;!isdigit(ch); ch = getchar()){
		if(ch == '-'){
			fl = -1;
		}
	}
	for(	; isdigit(ch); ch = getchar()){
		x = x * 10 + ch - '0';
	}
	x *= fl;
}