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

    点分治

    一般用于解决树上关于点对的问题(路径也可视作点对)。

    基础写法

    对于每个点对,我们在它的LCA处统计贡献。
    于是为了减小复杂度(具体不会证),我们每次找到当前联通块的重心,然后统计这个以这个点为LCA的点对的贡献。
    大致的结构就是这样:(随便找了一题代码放上来的)

    其中后面加了

    //~~~~~~
    

    的基本上都是一些基础的结构,在大多数题目中都是一样的。

    #include<bits/stdc++.h>
    using namespace std;
    #define R register int
    #define LL long long
    #define AC 100100
    #define ac 201000
    #define maxn 10000100
    
    int n, p, rot, ss, top1, top; LL ans;
    int Head[AC], date[ac], Next[ac], tot;
    int v[AC], bu[maxn], f[AC], Size[AC];
    bool z[AC];
    
    struct node{
        int sum, max;
    }s[ac], b[ac];
    
    inline bool cmp(node a, node b) {return a.max < b.max;}
    
    inline int read()
    {
        int x = 0;char c = getchar();
        while(c > '9' || c < '0') c = getchar();
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x;
    }
    
    inline void upmin(int &a, int b) {if(b < a) a = b;}
    inline void upmax(int &a, int b) {if(b > a) a = b;}
    inline void up(int &a, int b) {if(b >= p || b <= -p) b %= p; a += b; if(a < 0) a += p; if(a >= p) a -= p;}
    inline void imul(int &a, int b) {a = 1LL * a * b % p;}
    inline int ad(int a, int b) {if(b >= p || b <= -p) b %= p; a += b; if(a < 0) a += p; if(a >= p) a -= p; return a;}
    inline int mul(int a, int b) {return 1LL * a * b % p;}
    
    inline void add(int f, int w)
    {
        date[++ tot] = w, Next[tot] = Head[f], Head[f] = tot;
        date[++ tot] = f, Next[tot] = Head[w], Head[w] = tot;
    }
    
    void getrot(int x, int fa)//f[x]表示x子树中最重的那个的重量
    {
        f[x] = 0, Size[x] = 1;
        for(R i = Head[x]; i; i = Next[i])
        {
            int now = date[i];
            if(z[now] || now == fa) continue;
            getrot(now, x), Size[x] += Size[now];
            upmax(f[x], Size[now]);
        }
        upmax(f[x], ss - Size[x]);//因为无根,所以还要获得上面那一坨的重量
        if(f[x] < f[rot]) rot = x;
    }
    
    void dfs(int x, int fa, int w, int sum)//w为现在路径中的最大值 ,sum为路径权值在mod p意义下的权值和
    {
        /*do something*/
    }
    
    void cal(int x)
    {
        /*do something*/
    }
    
    void solve(int x)
    {
        cal(x);//~~~~~~
        for(R i = Head[x]; i; i = Next[i])
        {
            int now = date[i];
            if(z[now]) continue;
            rot = 0, f[0] = ss = Size[now];//~~~~~~
            getrot(now, 0), solve(rot);//~~~~~~
        }
    }
    
    void pre()
    {
        n = read(), p = read();
        for(R i = 2; i <= n; i ++) add(read(), read());
        for(R i = 1; i <= n; i ++) v[i] = read();
    }
    
    void work()
    {
        ans = n;//每个点单独算一次
        rot = 0, f[0] = ss = n;//~~~~~~
        getrot(1, 0), solve(rot);//~~~~~~
        printf("%lld
    ", ans);
    }
    
    int main()
    {
        //freopen("in.in", "r", stdin);
        pre();
        work();
        //fclose(stdin);
        return 0;
    }
    

    点分树

    点分树是一个严格log的树,可以用点分治来构造。
    假设我们当前所在节点是(x), 我们遍历它周围的各个子树,将这些子树内的重心作为(x)的儿子。
    最后就构建出了点分树。

    动态点分治

    因为点分树是一个严格log的树,所以如果我们修改了点(x),那我们就直接暴力重新统计(x)以及它的祖先节点的贡献,然后一般会在每个点上开个数据结构来维护一下子树内信息,复杂度是(O(nlog^2n))的。

  • 相关阅读:
    子类构造函数 supper关键字
    匿名内部类
    IK 分词器 源码分析
    java重写equals方法
    java编程思想
    设置centos7默认运行级别
    centos7配置wordpress
    python安装tkinter
    centos 7编译安装apache
    关于python中带下划线的变量和函数 的意义
  • 原文地址:https://www.cnblogs.com/ww3113306/p/10650253.html
Copyright © 2011-2022 走看看