zoukankan      html  css  js  c++  java
  • 树分治

    参考IOI2009《分治算法在树的路径中的应用》

    1. 点分治

     算法框架

    void getroot(int x, int fa) {
        sz[x] = 1, f[x] = 0;
        for(int i = 0; i < E[x].size(); i++) {
            int y = E[x][i].to;
            if(y == fa || vis[y]) continue;
            getroot(y, x);
            sz[x] += sz[y];
            f[x] = max(f[x], sz[y]);
        }
        f[x] = max(f[x], sum-sz[x]);    //sum为整个联通分量的大小,记录去除x后, 剩余联通分量的最大节点数
        if(f[x] < f[rt]) rt = x;        //更新当前重心
    }
    void solve(int x) { 
        vis[x] = 1;//将当前点标记
        for(int i = 0; i < E[x].size(); i++) {
            int y = E[x][i].to;
            if(vis[y]) continue ;
            sum = sz[y];//初始化sum为当前联通分量的大小
            getroot(x, rt = 0);//找连通块的重心
            solve(rt);//递归处理
        }
        vis[x] = 0;
    }
    int main() {
        build();//建树
        sum = f[0] = n;//初始化sum为当前联通分量的大小以及f[0], n个点
        getroot(1, rt = 0);//找重心
        solve(rt);//rt为重心, 点分治
    }    

    2. 边分治

     树中任意点的度数为D。当D为常数时,基于边分治的递归最坏情况下深度为O(logn)。通常D很小, 3~5左右。

    =======================================================================================

    POJ1741

    统计树中有多少对节点距离 <= k,树的点分治+容斥,时间复杂度O(nlognlogn), 内含O(nlogn)排序

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<iostream>
      4 #include<algorithm>
      5 #include<vector>
      6 using namespace std;
      7 
      8 const int N = 1e4+5;
      9 struct Edge {
     10     int to, w;
     11     Edge(int to, int w) : to(to), w(w){}
     12     Edge(){}
     13     bool operator < (const Edge &y) const {
     14         return w < y.w;
     15     }
     16 };
     17 vector<Edge> E[N];
     18 int sz[N], f[N], vis[N];
     19 int sum, rt;
     20 
     21 int d[N];
     22 int tmp[N], tot;
     23 
     24 int n, k, ans;
     25 
     26 void init() {//似乎不用init
     27     rt = ans = 0;
     28     for(int i = 0; i <= n; i++)
     29         E[i].clear();
     30     memset(f, 0, sizeof(f));
     31     memset(vis, 0, sizeof(vis));
     32     memset(sz, 0, sizeof(sz));
     33     memset(d, 0, sizeof(d));
     34     memset(tmp, 0, sizeof(tmp));
     35 }
     36 
     37 
     38 void getroot(int x, int fa) {
     39     sz[x] = 1, f[x] = 0;
     40     for(int i = 0; i < E[x].size(); i++) {
     41         int y = E[x][i].to;
     42         if(y == fa || vis[y]) continue;
     43         getroot(y, x);
     44         sz[x] += sz[y];
     45         f[x] = max(f[x], sz[y]);
     46     }
     47     f[x] = max(f[x], sum-sz[x]);    //sum为整个联通分量的大小,记录去除x后, 剩余联通分量的最大节点数
     48     if(f[x] < f[rt]) rt = x;        //更新当前重心
     49 }
     50 
     51 void getdeep(int x, int f) {
     52     tmp[tot++] = d[x];
     53     for(int i = 0; i < E[x].size(); i++) {
     54         int y = E[x][i].to, w = E[x][i].w;
     55         if(y == f || vis[y])continue;
     56         d[y] = d[x]+w;
     57         getdeep(y, x);
     58     }
     59 }
     60 int cal(int x, int now) {
     61     d[x] = now, tot = 0;
     62     getdeep(x, 0);
     63     sort(tmp,tmp+tot);
     64     int res = 0, l = 0, r = tot-1;
     65     while(l < r) {
     66         if(tmp[l]+tmp[r] <= k)
     67             res += r-l, l++;
     68         else r--;
     69     }
     70     return res;
     71 }
     72 void solve(int x) {
     73     ans += cal(x, 0);
     74     vis[x] = 1;
     75     for(int i = 0; i < E[x].size(); i++) {
     76         int y = E[x][i].to, w = E[x][i].w;
     77         if(vis[y]) continue ;
     78         ans -= cal(y, w);
     79         sum = sz[y];
     80         getroot(y, rt = 0);
     81         solve(rt);
     82     }
     83     vis[x] = 0;
     84 }
     85 int main() {
     86     while(~scanf("%d%d", &n, &k)) {
     87         if(n == 0&&k == 0) break;
     88         for(int i = 0; i <= n; i++) E[i].clear();
     89         for(int i = 1; i < n; i++) {
     90             int x, y, z;
     91             scanf("%d%d%d", &x, &y, &z);
     92             E[x].push_back(Edge(y, z));
     93             E[y].push_back(Edge(x, z));
     94         }
     95         ans = 0;
     96         sum = f[0] = n;//虚拟一个0节点, 但sum != n+1
     97         getroot(1, rt = 0);
     98         solve(rt);
     99         printf("%d
    ",ans);
    100     }
    101 }
    View Code

    树形dp

    链分治(树链剖分):修改点/链/子树,链支持快速合并,询问点/链/子树

    点分治:树根不固定

    DSU:树根固定

    http://hzwer.com/5984.html

    HDU4918

    lbn

  • 相关阅读:
    时间转换成时间戳
    元字符为名称的时候,使用两个反斜杠转义:\
    批量修改文件夹及文件用户权限和用户组权限 centos
    HDU6797 多校第三场 Tokitsukaze and Rescue
    AtCoder Regular Contest 103 E
    2020牛客第六场 B题 Binary Vector
    Codeforces Round #659 (Div. 2) B1. Koa and the Beach (Easy Version)
    Codeforces Round #659 (Div. 2) C. String Transformation 1
    Codeforces Round #659 (Div. 2) D GameGame
    P3194 [HNOI2008]水平可见直线 计算几何栈维护下凸壳
  • 原文地址:https://www.cnblogs.com/dirge/p/10005252.html
Copyright © 2011-2022 走看看