[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;
}
/**
**/




目录
相关文章
|
SQL 存储 算法
分库分表带来的问题
分库分表带来的问题
|
存储 缓存 NoSQL
Redis学习+集群搭建+持久化+主从复制(详细学习)(上)
Redis学习+集群搭建+持久化+主从复制(详细学习)(上)
218 0
|
弹性计算 缓存 搜索推荐
|
存储
408计算机组成原理学习笔记——中央处理器(二)
408计算机组成原理学习笔记——中央处理器
511 1
408计算机组成原理学习笔记——中央处理器(二)
|
算法
如何判断一个点是否在多边形内部?
如何判断一个点是否在多边形内部?
1354 0
|
负载均衡 Dubbo 应用服务中间件
|
网络协议 Linux 程序员
Linux下的UDP通信程序设计
任务 设计一个基于UDP的文件下载工具,client可从server处下载其路径下的文件 编码前的前置背景知识 实现两端上传下载的步骤 server端 接收将被下载的文件名称,并将该名称发送给client
300 0
|
存储 消息中间件 安全
构建便捷高效的宠物医疗预约服务平台:基于Spring Boot的实现
构建便捷高效的宠物医疗预约服务平台:基于Spring Boot的实现
构建便捷高效的宠物医疗预约服务平台:基于Spring Boot的实现

热门文章

最新文章