zoukankan      html  css  js  c++  java
  • CF980E The Number Games

    CF980E The Number Games

    给定一棵大小为 (n) 的树,第 (i) 个点的点权为 (2^i) ,删掉 (k) 个点及其连边,使得剩下的点组成一个连通块,且权值和最大,输出要删掉的点

    (n, kleq10^6)

    贪心,倍增,dfs序


    很容易想到一个贪心:不断删掉能被删除且权值最小的点,用堆实现

    但很明显这是错的:局部最优 ( eq) 全局最优

    因为点权为 (2^i) ,所以与其选择 (1, 2, cdots, i-1) 不如选 (i) 这一个点

    考虑这样一个 (O(n^2)) 贪心:从大往小确定不被删的点。以 (n) 为根,若当前枚举到的节点可选则将根到这个点的路径上的所有点都选掉

    可以发现,问题转化为了快速求出一个点是否可选,并标记路径

    因为最多会标记 (n-1) 条路径,所以可以暴力标记,倍增查询

    时间复杂度 (O(nlog n)) ,空间复杂度 (O(nlog n))

    原操作还有另一种实现方式:树状数组维护dfs序上每个点的距离,标记路径时修改子树内答案

    这种做法虽然略显繁琐,但是不失为一种常用的高效算法

    时间复杂度 (O(nlog n)) ,空间复杂度 (O(n))

    倍增代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 1e6 + 10;
    int n, k, fa[21][maxn]; bool vis[maxn];
    vector <int> e[maxn];
    
    void dfs(int u, int f) {
      fa[0][u] = f;
      for (int i = 1; i < 21; i++) {
        fa[i][u] = fa[i - 1][fa[i - 1][u]];
      }
      for (int v : e[u]) {
        if (v != f) dfs(v, u);
      }
    }
    
    int lca(int u) {
      int res = 0;
      for (int i = 20; ~i; i--) {
        if (!vis[fa[i][u]]) {
          u = fa[i][u], res |= 1 << i;
        }
      }
      return res;
    }
    
    int main() {
      scanf("%d %d", &n, &k);
      for (int i = 1, u, v; i < n; i++) {
        scanf("%d %d", &u, &v);
        e[u].push_back(v), e[v].push_back(u);
      }
      dfs(n, 0), vis[0] = 1;
      int tmp = n - k;
      for (int i = n; i; i--) {
        int t = lca(i);
        if (t < tmp) {
          int cur = i;
          while (!vis[cur]) {
            vis[cur] = 1, tmp--, cur = fa[0][cur];
          }
        }
      }
      for (int i = 1; i < n; i++) {
        if (!vis[i]) printf("%d ", i);
      }
      return 0;
    }
    

    dfs序+树状数组代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn = 1e6 + 10;
    int n, k, now, a[maxn], c[maxn], sz[maxn], fa[maxn], tid[maxn], dep[maxn]; bool vis[maxn];
    vector <int> e[maxn];
    
    void upd(int pos, int x) {
      for (; pos <= n; pos += pos & -pos) {
        c[pos] += x;
      }
    }
    
    int query(int pos) {
      int res = 0;
      for (; pos; pos &= pos - 1) {
        res += c[pos];
      }
      return res;
    }
    
    int dfs(int u, int f) {
      a[++now] = u, tid[u] = now, fa[u] = f, dep[u] = dep[f] + 1;
      for (int v : e[u]) {
        if (v != f) sz[u] += dfs(v, u);
      }
      return ++sz[u];
    }
    
    int main() {
      scanf("%d %d", &n, &k);
      for (int i = 1, u, v; i < n; i++) {
        scanf("%d %d", &u, &v);
        e[u].push_back(v), e[v].push_back(u);
      }
      dfs(n, 0), upd(1, -1);
      for (int i = 1; i <= n; i++) {
        upd(i, dep[a[i]] - dep[a[i - 1]]);
      }
      int tmp = n - k; vis[0] = 1;
      for (int i = n; i; i--) {
        if (query(tid[i]) < tmp) {
          for (int cur = i; !vis[cur]; tmp--, vis[cur] = 1, cur = fa[cur]) {
            upd(tid[cur], -1), upd(tid[cur] + sz[cur], 1);
          }
        }
      }
      for (int i = 1; i < n; i++) {
        if (!vis[i]) printf("%d ", i);
      }
      return 0;
    }
    
  • 相关阅读:
    从Oracle提供两种cube产品说开
    Sql Server DWBI的几个学习资料
    Unload Oracle data into text file
    初学Java的几个tips
    我常用的Oracle知识点汇总
    benefits by using svn
    如何在windows上使用putty来显示远端linux的桌面
    building commercial website using Microsoft tech stack
    Understand Thread and Lock
    Update google calendar by sunbird
  • 原文地址:https://www.cnblogs.com/Juanzhang/p/10344604.html
Copyright © 2011-2022 走看看