首页 > 其他分享 >Tree 树分治

Tree 树分治

时间:2023-01-06 17:33:08浏览次数:47  
标签:int mss 分治 Tree dfs2 first d2 d1

//题意:询问一棵树上长度不超过k的简单路径有多少条
// 思路:貌似可以用dsu on tree 但好像要用到平衡树之类的,之后再看看
//       https://tqltqltqlorzorzorz.blog.luogu.org/p4178-tree-ti-xie
//       在这里用的是树分治做法,分治过程不多说,主要是合并过程
//       我自己的写法是直接合并,每递归一层就利用二分算贡献,所以复杂度应该是达到了O(nlogn*logn),结果T了很多点
//       
//       对于这种题型可以再优化,利用容斥原理,本来为了保证一棵子树不对自己做贡献,都是做完这棵子树后再将这棵子树加入集合统计
//       但其实可以这样思考 总贡献=将所有情况加入的贡献-每棵子树内部自己的贡献 这样就不用在每层递归都二分一遍了,大大加快速度
//
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 50005;
vector<pair<int, int>> e[N];
namespace CenDec {
    int ctr, n, sz[N];
    bool del[N];
    void dfs(int p, int fa = 0) {
        sz[p] = 1;
        int mss = 0;
        for (auto to : e[p]) {
            if (del[to.first] || to.first == fa) continue;
            dfs(to.first, p);
            if (ctr != -1) return;//在子树递归过程中找到重心就即时退出
            mss = max(mss, sz[to.first]);
            sz[p] += sz[to.first];
        }
        mss = max(mss, n - sz[p]);//与根节点之上的那棵子树进行比较
        if (mss <= n / 2) {
            ctr = p;
            sz[fa] = n - sz[p];//更新sz[fa]的值,目的是把重心相邻的所有子树大小重新更新一遍,因为待会我们要
            //从这个重心向下分治,向下分治的话我们是需要用到子树大小的
        }
    }
    int k, cnt = 0;

    //注释掉的就是容斥写法,没注释掉的是自己的写法
   /* vector<int> d1, d2;

    void dfs2(int x, int fa, int w) {
        if(w>k) return ;
        d1.push_back(w);
        d2.push_back(w);
        for (auto y : e[x]) {
            if (del[y.first] || y.first == fa) continue;
            dfs2(y.first, x, w + y.second);
        }
    }
    int calc(vector<int>& d) {
        sort(d.begin(), d.end());
        int m = d.size();
        int r = m - 1, ans = 0;
        for (int i = 0; i < m; i++) {
            while (r >= 0 && d[i] + d[r] > k) --r;
            if (i < r) ans += r - i;
        }
        return ans;
    }*/
    int d1[N], d2[N], cnt1, cnt2;//已知长度,暂存长度
    void dfs2(int x, int fa, int w) {
        if (w > k) return;
        d2[++cnt2] = w;
        sort(d1, d1 + cnt1 + 1);
        int ned = k - w;
        int temp = lower_bound(d1, d1 + cnt1 + 1, ned) - d1;
        cnt += temp;
        for (auto y : e[x]) {
            if (del[y.first] || y.first == fa) continue;
            dfs2(y.first, x, w + y.second);
        }
    }

    void run(int p) {
        /*d1.push_back(0);
        for (auto y : e[p]) {
            if (del[y.first]) continue;
            d2.clear();
            dfs2(y.first, p, y.second);
            cnt -= calc(d2);
        }
        cnt += calc(d1);
        d1.clear();*/

        d1[0] = 0;
        for (auto x : e[p]) {
            if (del[x.first]) continue;
            dfs2(x.first, p, x.second);
            for (int i = 1; i <= cnt2; i++) d1[++cnt1] = d2[i];
            cnt2 = 0;
        }
        cnt1 = 0;

        del[p] = 1;
        for (auto to : e[p]) {
            if (!del[to.first]) {
                n = sz[to.first];
                ctr = -1;
                dfs(to.first);
                run(ctr);
            }
        }
    }
    int count(int n0, int k0) {
        n = n0, k = k0; ctr = -1;
        dfs(1);//找重心
        run(ctr);//计算贡献
        return cnt;
    }
}
signed main() {
    int n, k, u, v, w;
    cin >> n;
    for (int i = 1; i <= n - 1; ++i)
    {
        cin >> u >> v >> w;
        e[u].push_back({ v,w });
        e[v].push_back({ u,w });
    }
    cin >> k;
    cout << CenDec::count(n, k) << endl;
    return 0;
}

 

标签:int,mss,分治,Tree,dfs2,first,d2,d1
From: https://www.cnblogs.com/Aacaod/p/17031154.html

相关文章

  • Race 树分治写法
    //题意:一棵树有边权,询问一条长度为k的简单路径所需的最小步数//思路:点分治,主要是合并的思路,因为是要求最小步数,所以我们对于每一种长度记最小步数即可//#include<bi......
  • Race dsu on tree写法
    //跑不过,不知道为啥,感觉逻辑都很正确了//题意:给出一棵带边权的树,询问一条权值为k的路径经过点的最小值是多少//思路:因为涉及到最小值问题,所以树性dp好像不行(其实暂时......
  • 单细胞 | CNV和SNV(genome + MT)推测lineage tree
     正式进入cancergenomics领域,只不过是从scRNA-seq与scATAC-seq入手。我们的问题是如何从有限的SNV和CNV数据里推测出CRC的lineage的关系。 使用的工具:https://git......
  • C#(Java)将List集合构建成Tree树
    C#(Java)将List集合构建成Tree树子安树构建算法,可以通过空间换时间进一步优化速度树结构的类publicclassMyTreeNode{publicMyTreeNode(long?iD,long?pare......
  • NERDtree 快捷键
    NERDtree操作指令ctrl+w+h光标focus左侧树形目录ctrl+w+l光标focus右侧文件显示窗口ctrl+w+w光标自动在左右侧窗口切换ctrl+w+r......
  • C#实现treeview节点上下左右自由移动
    以下是节点移动类NodeMove.cs源码:usingSystem;usingSystem.Collections.Generic;usingSystem.Text;usingSystem.Windows.Forms;usingSystem.Collections;namespaceNo......
  • C#实现TreeView向XML的绝对转换类
    从第一次接触XML开始就想写一个能实现tree和XML灵活转换的类了。写这个类大概用去了将近半天的时间,花的时间有些长了。呵呵。。好在收获颇多,熟练了XML的读写类,对C#中的forea......
  • ExtJS-UI组件-TreePanel
    ExtJS教程汇总:https://www.cnblogs.com/cqpanda/p/16328016.html转载请注明出处:https://www.cnblogs.com/cqpanda/p/16587500.html更新记录2023年1月2日从笔记迁移到......
  • element ui --el-select 嵌套el-tree多选联动、删除联动
    需求:el-select下拉框嵌套el-tree树形组件完成多选、删除、搜索、清空选项等联动功能。特殊需求:(当子节点全部选中时el-select中只展示父节点tag,el-tree组件父子节点全......
  • 关于sourcetree 代码库更改用户密码后报fatal:Authentication failed for 的问题
      解决方案:**重置sourceTree密码:**找到sourceTree的安装目录将C:\Users\USERNAME\AppData\Local\Atlassian\SourceTree并删除passwd文件(记得把sourceTree关......