社区讨论

萌新求条,悬赏10rmb

P14706[ICPC 2023 Tehran R] Cup of Tea参与者 7已保存回复 23

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
23 条
当前快照
1 份
快照标识符
@mkoa3r1u
此快照首次捕获于
2026/01/22 01:10
4 周前
此快照最后确认于
2026/01/22 19:08
4 周前
查看原帖
CPP
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n,k,st[300005][25],deep[300005],deep2[300005],sz[300005],rt,vis[300005],N,cdfa[300005],p[300005],Dist[300005];
bool flag[300005],flag2[300005];
vector<int> premin[300005];
vector<pair<int,int> > e[300005],v[300005],v2[300005];
struct node{
    int id,dis;
    bool operator < (const node & a) const{
        return dis > a.dis;
    }
};
void getrt(int x,int fa){
	sz[x] = 1;
	int maxn = 0;
	for (auto i : e[x]) if (!vis[i.first] && i.first != fa){
		getrt(i.first,x);
		maxn = max(maxn,sz[i.first]);
		sz[x] += sz[i.first];
	}
	if (max(maxn,N - sz[x]) <= N / 2) rt = x;
}
void getsz(int x,int fa){
	N++;
	for (auto i : e[x]) if (!vis[i.first] && i.first != fa) getsz(i.first,x);
}
int lca(int x,int y){
    if (deep[x] < deep[y]) swap(x,y);
    int cnt = deep[x] - deep[y];
    for (int i = 20;i >= 0;i--) if (cnt >= (1 << i)){
        cnt -= (1 << i);
        x = st[x][i];
    }
    if (x == y) return x;
    for (int i = 20;i >= 0;i--){
        if (st[x][i] == st[y][i]) continue;
        x = st[x][i];
        y = st[y][i];
    }
    return st[x][0];
}
int dis(int x,int y){
	return deep2[x] + deep2[y] - deep2[lca(x,y)] * 2;
}
void dfs(int x,int fa){
	for (auto i : e[x]) if (i.first != fa){
		st[i.first][0] = x;
		deep[i.first] = deep[x] + 1;
		deep2[i.first] = deep2[x] + i.second;
		dfs(i.first,x);
	}
}
void getdis(int x,int fa,int dis,int id){
	if (flag[x]) v[id].push_back({dis,x});
	for (auto i : e[x]) if (!vis[i.first] && i.first != fa) getdis(i.first,x,dis + i.second,id);
}
void dfs2(int x){
	vis[x] = true;
	getdis(x,-1,0,x);
	sort(v[x].begin(),v[x].end());
	for (auto i : e[x]) if (!vis[i.first]){
		N = 0;
		getsz(i.first,-1);
		getrt(i.first,-1);
		cdfa[rt] = x;
		dfs2(rt);
	}
}
void dij(){
	priority_queue<node> q;
	memset(Dist,0x3f,sizeof(Dist));
	Dist[1] = 0;
	flag2[1] = true;
	q.push({1,0});
	while (!q.empty()){
		int x = q.top().id,d = q.top().dis,tmp;
		q.pop();
		tmp = x;
		while (tmp){
			int dist = dis(x,tmp),rem;
			rem = k - dis(x,tmp);
			if (rem >= 0) while (p[tmp] < v[tmp].size() && v[tmp][p[tmp]].first <= rem){
				flag2[v[tmp][p[tmp]].second] = true;
				if (Dist[v[tmp][p[tmp]].second] > d + dist + v[tmp][p[tmp]].first){
					Dist[v[tmp][p[tmp]].second] = d + dist + v[tmp][p[tmp]].first;
					q.push({v[tmp][p[tmp]].second,Dist[v[tmp][p[tmp]].second]});
				}
				p[tmp]++;
			}
			tmp = cdfa[tmp];
		}
	}
}
main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
    cin >> n >> k;
	for (int i = 1;i < n;i++){
		int u,v,w;
        cin >> u >> v >> w;
		e[u].push_back({v,w});
		e[v].push_back({u,w});
	}
	for (int i = 1;i <= n;i++) cin >> flag[i];
	dfs(1,-1);
	for (int j = 1;j <= 20;j++) for (int i = 1;i <= n;i++) st[i][j] = st[st[i][j - 1]][j - 1];
	N = n;
    getrt(1,-1);
    dfs2(rt);
	dij();
	for (int i = 1;i <= n;i++) if (flag2[i]){
		int tmp = i;
		while (tmp){
			int dist = dis(i,tmp);
			v2[tmp].push_back({dist,Dist[i] + dist});
			tmp = cdfa[tmp];
		}
	}
	for (int i = 1;i <= n;i++) if (!v2[i].empty()){
		sort(v2[i].begin(),v2[i].end());
		premin[i].push_back(v2[i][0].second);
		for (int j = 1;j < v2[i].size();j++) premin[i].push_back(min(premin[i].back(),v2[i][j].second));
	}
	for (int i = 2;i <= n;i++){
		int minn = LONG_LONG_MAX;
		int tmp = i;
		while (tmp){
			int dist = dis(i,tmp),rem;
			rem = k - dist;
			if (rem >= 0 && !v2[tmp].empty()){
				auto it = upper_bound(v2[tmp].begin(),v2[tmp].end(),make_pair(rem,LONG_LONG_MAX));
				if (it != v2[tmp].begin()){
					int pos = it - v2[tmp].begin() - 1;
					minn = min(minn,premin[tmp][pos] + dist);
				}
			}
			tmp = cdfa[tmp];
		}
		cout << (minn == LONG_LONG_MAX ? -1 : minn) << " ";
	}
	return 0;
}
思路就是建立点分树,用dij求出可以到达的商店的最短路。利用点分树结构对于每个重心收集其分支区域内所有可以到达的商店。查询就是遍历其点分树上的祖先,满足条件的最小代价。
呜呜呜求助

回复

23 条回复,欢迎继续交流。

正在加载回复...