[ICPC 46th Shanghai] Life is a Game 克鲁斯卡尔重构树

简介: 题目大意:给定n个点,m条边,有q个询问每个点有一个(能量值)点权,每条边有一个边权m条边描述为u v w表示有一条u与v相连的边权为w的通路在每一次询问中,给定一个点x和现有的能量值k,每次只能是在当前能量值大于边权的时候到达另一个点,并获取这个点的能量值(路可以重复走),问最终能够获得多大的能量值

题目链接


题目大意:


给定n个点,m条边,有q个询问

每个点有一个(能量值)点权,每条边有一个边权

m条边描述为u v w表示有一条u与v相连的边权为w的通路


在每一次询问中,给定一个点x和现有的能量值k,每次只能是在当前能量值大于边权的时候到达另一个点,并获取这个点的能量值(路可以重复走),问最终能够获得多大的能量值


思路:


克鲁斯卡尔重构树

在建立克鲁斯卡尔重构树的时候,会将边权化为点权来处理并建立成一个堆,而且原先的节点一定是重构树中的 叶子节点 ,除了叶子节点之外的其他点都是原先的边权

在克鲁斯卡尔重构树中,从叶子节点以上到根的路径中,点权一定是单调不减的


所以说给定的节点要是能够直接跳到祖先节点的话,那么说以这个节点为根的子树都能够访问到

所以说在这里可以使用倍增来处理,并且在维护以某节点为根的子树的所有节点的能量值

这样如果说能够跳过去的话,就将能量值的贡献加过去,直到不能跳为止


code:


ll fa[maxn],siz[maxn],a[maxn];
vector<int> gra[maxn];
ll bz[27][maxn],n,m,cnt,q;
struct node {
  int u,v,w;
  friend bool operator<(node a,node b) {
    return a.w < b.w;
  }
  node() {  }
  node(int _u,int _v,int _w) {
    u = _u,v = _v,w = _w;
  }
};
vector<node> vet;
int get(int x) {
  if(x == fa[x]) return x;
  else return fa[x] = get(fa[x]);
}
void init() {
  for(int i=0; i<=n*2; i++) fa[i] = i;//,siz[i] = 1;
}
void kru() {
  sort(vet.begin(),vet.end());
  for(int i=0; i<m; i++) {
    node nd = vet[i];
    int u = nd.u,v = nd.v,w = nd.w;
    int fau = get(u);
    int fav = get(v);
    if(fau != fav) {
      a[++cnt] = w;
      fa[cnt] = fa[fau] = fa[fav] = cnt;
      gra[fau].push_back(cnt);
      gra[cnt].push_back(fau);
      gra[fav].push_back(cnt);
      gra[cnt].push_back(fav);
    }
  }
}
void dfs(int u,int fa) {
  bz[0][u] = fa;
  for(int i=1; i<=20; i++) {
    bz[i][u] = bz[i-1][bz[i-1][u]];
  }
  for(int to:gra[u]) {
    if(to == fa) continue;
    dfs(to,u);
    siz[u] += siz[to];
  }
}
int main() {
  n = read,m = read,q = read;
  init();
  cnt = n;
  for(int i=1; i<=n; i++) siz[i] = read;
  for(int i=1; i<=m; i++) {
    int u = read,v = read,w = read;
    vet.push_back(node {u,v,w});
  }
  kru();
  dfs(cnt,0);
  a[0] = ((1LL<<31)-1);
  for(int i=1; i<=q; i++) {
    ll u = read,s = read;
    ll now = s + siz[u];
    while(u != cnt) {
      int tu = u;
      for(int i=20; i>=0; i--) {
        if(a[bz[i][u]] <= now) u = bz[i][u];
      }
      if(tu == u) break;
      now = siz[u] + s;
    }
//    printf("->>>> %lld\n",now);
        printf("%lld\n",now);
  }
  return 0;
}
/**
**/




目录
相关文章
(数学)(必要解题步骤)2021icpc上海D. Strange Fractions
(数学)(必要解题步骤)2021icpc上海D. Strange Fractions
77 0
|
消息中间件 uml
gym102394 2019CCPC哈尔滨 A. Artful Paintings(二分 差分约束 优化)
gym102394 2019CCPC哈尔滨 A. Artful Paintings(二分 差分约束 优化)
160 0
AtCoder Beginner Contest 223 D - Restricted Permutation(建图 思维 构造 拓扑排序)
AtCoder Beginner Contest 223 D - Restricted Permutation(建图 思维 构造 拓扑排序)
127 0
|
机器学习/深度学习
AtCoder Beginner Contest 218 F - Blocked Roads (最短路径还原 思维)
AtCoder Beginner Contest 218 F - Blocked Roads (最短路径还原 思维)
98 0
2020 ICPC Asia Taipei-Hsinchu Site Programming Contest H. Optimization for UltraNet (二分+最小生成树+算贡献)
2020 ICPC Asia Taipei-Hsinchu Site Programming Contest H. Optimization for UltraNet (二分+最小生成树+算贡献)
125 0
|
机器学习/深度学习 人工智能 决策智能
LDU2019第一次质检——CoolGuang‘s Good Game(思维+区间DP)
LDU2019第一次质检——CoolGuang‘s Good Game(思维+区间DP)
108 0
|
人工智能 算法 BI
算法比赛模拟题精解之“Tairitsu and Dynamic Objects”
根据题意,分析得知,Hikari 和 Tairitsu 每次会优先选择 ai+bi 的值最大的物品,当物品的 ai+bi 值相等时,选择bi大的那个。