标签:CCPC2021 pre Monkey int 查集 deson son map1 权值
本题可以根据权值最大的点作为突破口,权值最大的点一定是最优解的最后一步,那么我们可以依次倒推,每次删去最大的点以及该点连接的边最后推到每一个点。
实现过程:我们可以将所有点按照权值从小到大排出,每次枚举出的新点因为权值比前面的大,所以可以将他作为原先连通块的新祖宗,这样在搜寻深度倒推的时候就能够实现优先删除一个连通块中权值较大的点,再删除权值较小的点,每次倒推与该点相连的点的时候,与该点相连的点的深度为该点深度加1,直到倒推到无法倒推。
代码:
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
const int M = 100010;
typedef pair<int, int>PII;
vector<int> next1[M], next2[M];
PII map1[M];
int pre[M];
bool vis[M];
int len[M];
void init(int n) {
for (int i = 1; i <= n; ++i) {
pre[i] = i;
next1[i].clear();
next2[i].clear();
}
}
int find(int son) {
int deson, dad1;
deson = son;
while(son != pre[son]) son = pre[son];
while(deson != pre[deson]) {
dad1 = pre[deson];
pre[deson] = son;
deson = dad1;
}
return son;
}
void find_depth(int now) {
for (int i : next2[now]) {
len[i] = len[now] + 1;
find_depth(i);
}
}
int main() {
int t;
scanf("%d", &t);
while(t--) {
int n, u, v;
scanf("%d", &n);
init(n);
for (int i = 0; i < n - 1; ++i) {
scanf("%d%d", &u, &v);
next1[u].push_back(v); next1[v].push_back(u);
}
for (int i = 1; i <= n; ++i) {
scanf("%d", &map1[i].first);
map1[i].second = i;
}
sort(map1 + 1, map1 + 1 + n); // 按照点权值从小到大排序
memset(vis, false, sizeof(vis));
vis[map1[1].second] = true;
int temp1;
for (int i = 2; i <= n; ++i) {
int temp = map1[i].second;
for (int j : next1[temp]) {
if(!vis[j]) continue;
temp1 = find(j);
pre[temp1] = temp;
next2[temp].push_back(temp1);
}
vis[temp] = 1;
}
memset(len, 0, sizeof(len));
len[map1[n].second] = 1;
find_depth(map1[n].second);
for (int i = 1; i <= n; ++i) printf("%d\n", len[i]);
}
return 0;
}
标签:CCPC2021,pre,Monkey,int,查集,deson,son,map1,权值 来源: https://blog.csdn.net/sdtbu_jk19/article/details/120833717
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。