yuwj  

写在前面

好像不能传播题解,然后这是我自己补的上周那场区域赛,应该没问题吧

怎么说呢,反正 vp 打铁 3 题,补题银牌就补不动了

这里就只放下代码了

该加训了,但是说实话这个难度我是真没训过,写不出也正常,多校也写不出铜牌题,哎哎哎

虽然现在是青名,但是还是只能做出签到题吗,铜牌题感觉得有 CF 2200 了吧,我现在还没真正出过这个难度分段的题目

L

// 多边形合法条件是,其他所有边的和 > 最大边
// 对于每个 k,本质上就是选择最大的 k 条边使得这个多边形成立,即
// 设最大的边长为 a_r,则 a_r < sum(r-k+1,r-1)
// 对于固定的 r,设定阈值为 th < pre[r-1] - a_r,设最大的 t < r,使 pre[t] < th
// 最小的可行的 k 就是,k(r) = r - t
// 就是对每个 k 选择最大的 r,满足 k \in [k(r), r],这样周长 pre[k] - pre[r - k] 最大
void Solve(){
	cin >> n;
	vector<int> num(n+1);
	For(i,1,n) cin >> num[i];

	if(n < 3){
		for(int i=1;i<=n;++i) cout << 0 << " \n"[i==n];
		return;
	}

	sort(num.begin()+1,num.end());

	vector<int> pre(n+1), suf(n+2);
	for(int i=1;i<=n;++i) pre[i] = pre[i-1] + num[i];
	
	vector<int> ans(n+1);

	vector<vector<int>> pos(n+1);
	for(int i = 3; i <= n; ++i){
		int now = pre[i-1] - num[i];
		int id = lower_bound(all(pre), now) - pre.begin() - 1;
		int k = max(3ll, i - id);
		if(k <= i)pos[k].pb(i);
	}

	priority_queue<int> pq;
	for(int k = 3; k <= n; ++k){
		for(auto r : pos[k]) pq.push(r);
		
		while(pq.size() && pq.top() < k) pq.pop();
		
		if(pq.size()){
			auto r = pq.top();
			ans[k] = pre[r] - pre[r-k];
		}
	}

	For(i,1,n) cout << ans[i] << " \n"[i==n];
}

J

struct Info{
	int mn, u, nmn, v;
}info[Maxn];

int up[Maxn][25],dep[Maxn],cost[Maxn];
void dfs(int u,int fa){
    up[u][0] = fa;
    For(i,1,20) up[u][i] = up[up[u][i-1]][i-1];
    for(auto v : G[u]){
        if(v==fa) continue;
        dep[v] = dep[u] + 1;
		if(cost[v] < info[u].mn) info[u].nmn = info[u].mn, info[u].v = info[u].u, info[u].mn = cost[v], info[u].u = v;
		else if(cost[v] < info[u].nmn) info[u].nmn = cost[v], info[u].v = v;
        dfs(v,u);
    }
}

int get(int step,int x){
    int y = x;
    for(int i=20;i>=0;--i){
        if(step>=(1<<i)) y = up[y][i], step -= (1<<i);
    }
    return y;
}

// 1.u,v提高到相同深度,就是按 pw[2] 从大往小减少深度即可
// 	如果此时两点相同说明在同一条链上,直接返回即可
// 2.一起往上跳直到在lca下方
int LCA(int u,int v){
	if(dep[u] < dep[v]) swap(u,v);
	int d = dep[u] - dep[v];

	for(int i=20;i>=0;--i){
		if(d & (1ll<<i)) u = up[u][i];
	}
	
	if(u == v) return u;
	
	for(int i = 20; i>=0;--i){
		if(up[u][i] != up[v][i]){
			u = up[u][i], v = up[v][i];
		}
	}

	return up[u][0];
}

void Solve(){
	cin >> n >> m; For(i,1,n) G[i].clear(), info[i] = {INT_MAX,0,INT_MAX,0};
	For(i,1,n) cin >> cost[i];

	For(i,1,n-1) cin >> u >> v, G[u].pb(v), G[v].pb(u);

	function<void(int,int)> DP = [&](int u,int fa) -> void{
		int mn = INT_MAX, nmn = INT_MAX;
		for(auto v : G[u]){
			if(v == fa) continue;
			DP(v,u);
			if(cost[v] < mn) nmn = mn, mn = cost[v];
			else if(cost[v] < nmn) nmn = cost[v];
		}
		cost[u] = min(cost[u], mn + nmn);
	};

	DP(1,0);

	dfs(1,0);

	// For(i,1,n) cerr << cost[i] << " \n"[i == n];

	vector<int> sum(n+1,LLONG_MAX), d(n+1);

	function<void(int,int)> dfs2 = [&](int u,int fa) -> void{
		for(auto v : G[u]){
			if(v == fa) continue;
			sum[v] = min(sum[v], sum[u] + (v != info[u].u ? info[u].mn : info[u].nmn));
			dfs2(v,u);
		}
	};

	sum[1] = cost[1];
	// cerr << info[1].nmn << '\n';
	dfs2(1,0);
	// For(i,1,n) cerr << sum[i] << " \n"[i==n];

	while(m--){
		cin >> x >> y;
		
		if(LCA(x, y) != y) {cout << "-1\n"; continue;}
		
		cout << (sum[x] - sum[y]) << '\n';
	}
}

I

// 不存在第三个点作为中间点使得 i,j (i ^ k) ^ (k ^ j) = (i ^ j)
// A[u][v] ^ A[u][R] ^ A[v][R] = lca,留下的点
int A[2005][2005];
void Solve(){
	cin >> n;
	for(int i = 1; i <= n; ++i){
		for(int j = i; j <= n; ++j){
			cin >> A[i][j];
			A[j][i] = A[i][j];
		}
	}

	function<int(int,int)> lca = [&](int u, int v) -> int{
		return A[u][v] ^ A[u][1] ^ A[1][v];
	};

	vector<pii> ans;
	
	for(int v = 2; v <= n; ++v){
		int p = -1;
		
		for(int u = 1; u <= n; ++u) if(v != u){
			if(lca(u,v) == u){
				if(p == -1) p = u;
				else{
					int fa = lca(p,u);
					if(fa == p) p = u;
				}
			}
		}

		ans.pb({p,v});
	}

	for(auto [u,v] : ans) cout << u << ' ' << v << '\n';
}

F

// 每次都处理最早的事件,处理相向事件和已经停止的事件
struct Event{
	int time, op, id;
	bool operator>(const Event o) const{
		return time > o.time;	
	};
};

void Solve(){
	cin >> n; For(i,1,n) G[i].clear();
	vector<int> t(n+1), dir(n+1), a(n+1);
	For(i,1,n) cin >> t[i], G[t[i]].pb(i);
	For(i,1,n) cin >> a[i];
	
	For(i,1,n) dir[i] = (a[t[i]] > a[i] ? 1 : -1);

	priority_queue<Event,vector<Event>,greater<>> pq;

	auto D = [&](int i)->int{
		return abs(a[i] - a[t[i]]);
	};

	for(int i = 1; i <= n; ++i) if(dir[i] != dir[t[i]]) pq.push({D(i),0,i});

	vector<int> ans(n+1,-1);

	int cnt = 0;

	auto work = [&](int u,int T){
		if(ans[u] != -1) return;
		ans[u] = T, cnt++;
		for(auto v : G[u]){ // 对所有儿子处理未停止的,相向而行,还是同向而行
			int nT, d = D(v);
			if(dir[v] == dir[u]){
				nT = ans[u] + 2*d;
			}else{
				nT = (ans[u] < d ? 2*d - ans[u] : d);
			}
			pq.push({nT, 1, v});
		}
	};

	while(cnt < n){
		auto [T, op, id] = pq.top(); pq.pop();
		
		if (ans[id] != -1) continue;

		if(op == 0){ // 相向而行
			int d = D(id);
			if(ans[t[id]] != -1 && ans[t[id]] < d){ // 如果目标更早停止,则变成追静止
				pq.push({2*d - ans[t[id]], 1, id});
			}else{
				work(id,d); // 否则就可以直接作为答案时间
			}
		}else{ // 已经停止了
			work(id, T);
		}
	}

	For(i,1,n) cout << ans[i] << " \n"[i == n];
}

写在最后

训练难度该加强了,天天捧着 1600 - 1800 也做不出难题,虽然这个分段自己的出题率也可能才 40% ?

还要写作业,就这样了,该训了

posted on 2025-10-26 17:31  xiaowang524  阅读(1)  评论(0)    收藏  举报