(有注释)把vec存图改成链式前向星后 #13从TLE变成RE求调
查看原帖
(有注释)把vec存图改成链式前向星后 #13从TLE变成RE求调
1081824
LoveFrieren楼主2024/8/24 11:22

思路:跟题解差不多,有注释

#include<bits/stdc++.h>
using namespace std;
const int M = 3e5 + 10; typedef pair<int, int> pii;
struct edge {
	int to, vl, next;
}tr[M];
int n, m, tot, bchf[M], val[M], d[M], wson[M], sz[M], tp[M], fa[M], dist[M], h[M];
inline void read(int &a) {//快读 
	int f = 1; a = 0;
	char c = getchar();
	while (c < '0' || c > '9') {
		if (c == '-') f == -1;
		c = getchar();
	}
	while ( c >= '0' && c <= '9') {
		a = (a << 1) + (a << 3) + (c ^ 48);
		c = getchar();
	}
}
void dfs(int u, int f) {//求出深度,重儿子(重链剖分用),与根节点距离(求路径长度用) 
	d[u] = d[f] + 1;
	sz[u] = 1; fa[u] = f;
	dist[u] = dist[f] + val[u];
	for(int i = h[u]; i; i = tr[i].next){
		int v = tr[i].to;
		if (v == f) continue;
		val[v] = tr[i].vl;
		dfs(v, u);
		sz[u] += sz[v];
		if(sz[u] > sz[wson[u]]) wson[u] = v;
	}
}
void gtop(int u, int f, int topp) {//重链的顶 
	tp[u] = topp;
	if (wson[u] != 0){
		gtop(wson[u], u, topp);
		for(int i = h[u]; i; i = tr[i].next) {
			int v = tr[i].to;
			if (v == wson[u] || v == f) continue;
			gtop(v, u, v);
		}
	}
}
int glca(int u, int v) {//求LCA 
	while(tp[u] != tp[v]) {
		if(d[tp[u]] < d[tp[v]])swap(u, v);
		u = fa[tp[u]];
	}
	return d[u] > d[v] ? v : u;
}//there is a struct  
struct a_query {
	int sta, end, dis;
	a_query(int st, int en){
		this -> sta = st;
		this -> end = en;
		this -> dis = dist[sta] + dist[end] - (dist[glca(st, en)] << 1);
	}
	a_query(){};
} qry[M];
void gpre_sum(int u){//求前缀和,得出每个边经过的次数 
	for(int i = h[u]; i; i = tr[i].next){
		int v = tr[i].to;
		if (v == fa[u]) continue;
		gpre_sum(v);
		bchf[u] += bchf[v]; 
	}
}
bool check(int t){
	int cnt = 0, dismx = -1, mx = -1, demand;
	memset(bchf, 0, sizeof(bchf));
	for(int i = 1; i <= m; ++i)
		if(qry[i].dis > t){//只统计长度超过t的 
			bchf[qry[i].sta]++, bchf[qry[i].end]++, bchf[glca(qry[i].sta, qry[i].end)] -= 2;
			++cnt; dismx = max(dismx, qry[i].dis);
		}//边差分求各边经过次数 
	gpre_sum(1); 
	demand = dismx - t;
	for(int i = 1; i <= n; ++i)
		mx = max(mx, bchf[i]);//求出经过次数最多的 
	if(mx < cnt) return 0;//如果各边没有交,肯定不行 
	for(int i = 1; i <= n; ++i)
		if(cnt == bchf[i] && val[i] >= demand)
			return 1;//如果存在一个交,它的长度比需要减去的大,就可以 
	return 0;//否则不行 
}
int main() {
	read(n), read(m); int l = 0, r = -1;
	for(int i = 1, u, v, ti; i < n; ++i){
		read(u), read(v), read(ti);
		tr[++tot].next = h[u];
		tr[tot].to = v; h[u] = tot; tr[tot].vl = ti;
		tr[++tot].next = h[v];
		tr[tot].to = u; h[v] = tot; tr[tot].vl = ti;
	}//scan 
	dfs(1, 0); gtop(1, 0, 1); ++r;
	for(int i = 1, u, v; i <= m; ++i){
		read(u), read(v);
		a_query in(u, v);
		qry[i] = in; r = max(r, in.dis);
	}//scan 询问 
	while(l < r){
		int mid = l + (r - l >> 1);
		if(check(mid)) r = mid;
		else l = mid + 1;
	}//二分 
	cout << l;
	return 0;
}
2024/8/24 11:22
加载中...