标签: 点分治

  • BZOJ 2870 最长道路

    BZOJ什么垃圾机器….DBZOJ都能A,BZOJ T飞

    上来直接点分就行了,用动态开点线段树维护已经出现过的最小值为x的最长的路径。

    然后合并的时候,拿一个路径去和最小值大于等于他的更新答案即可。

    #include <algorithm>
    #include <cstdio>
    #include <iostream>
    #include <vector>
    typedef long long int int_t;
    using std::cin;
    using std::cout;
    using std::endl;
    const int_t INF = 0x7fffffff;
    const int_t LARGE = 1e5;
    const int_t RANGE = 65536;
    struct Data {
        int depth;
        int val;
        Data(int depth = -1, int val = 1) {
            this->depth = depth;
            this->val = val;
        }
    };
    std::ostream& operator<<(std::ostream& os, const Data& data) {
        os << "Data{depth=" << data.depth << ",val=" << data.val << "}";
        return os;
    }
    void* allocate();
    struct Node {
        int begin;
        int end;
        int value;
        Node *left, *right;
        Node(int begin, int end) {
            this->begin = begin;
            this->end = end;
            value = -INF;
            left = right = NULL;
        }
        void maintain() {
            value = -INF;
            if (left) value = std::max(value, left->value);
            if (right) value = std::max(value, right->value);
        }
        int query(int begin, int end) {
            if (end < this->begin || begin > this->end) return -INF;
            if (this->begin >= begin && this->end <= end) return this->value;
            int result = -INF;
            if (left) result = std::max(result, left->query(begin, end));
            if (right) result = std::max(result, right->query(begin, end));
            return result;
        }
        void maxTo(int pos, int val) {
            if (begin == end) {
                this->value = std::max(value, val);
                return;
            }
            int mid = (begin + end) / 2;
            if (pos <= mid) {
                if (left == NULL) left = new (allocate()) Node(begin, mid);
                left->maxTo(pos, val);
            } else {
                if (right == NULL) right = new (allocate()) Node(mid + 1, end);
                right->maxTo(pos, val);
            }
            maintain();
        }
    };
    int used = 0;
    void* allocate() {
        static char buf[LARGE * 20 * sizeof(Node)];
        return buf + (used++) * sizeof(Node);
    }
    int vals[LARGE + 1];
    bool removed[LARGE + 1];
    int size[LARGE + 1];
    std::vector<int> graph[LARGE + 1];
    int n;
    //统计子树大小和路径长度及权值
    void DFS1(int vtx, int from, int depth, std::vector<Data>& vec,
              int minval = INF, bool save = false) {
        minval = std::min(minval, vals[vtx]);
        if (save) vec.push_back(Data(depth, minval));
        size[vtx] = 1;
        for (int i = 0; i < graph[vtx].size(); i++) {
            int to = graph[vtx][i];
            if (to != from && removed[to] == false) {
                DFS1(to, vtx, depth + 1, vec, minval, save);
                size[vtx] += size[to];
            }
        }
    }
    void DFS2(int vtx, int from, int& size, int& center, int rootSize = -1) {
        if (rootSize == -1) {
            rootSize = ::size[vtx];
            size = INF;
        }
        int maxSize = rootSize - ::size[vtx];
        for (int i = 0; i < graph[vtx].size(); i++) {
            int to = graph[vtx][i];
            if (to != from && removed[to] == false) {
                maxSize = std::max(maxSize, ::size[to]);
                DFS2(to, vtx, size, center, rootSize);
            }
        }
        if (maxSize < size) {
            size = maxSize;
            center = vtx;
        }
    }
    int_t DFS3(int vtx) {
        int center, size;
        static std::vector<Data> vec;
        DFS1(vtx, -1, 1, vec);
        DFS2(vtx, -1, size, center);
        int_t result = -INF;
        removed[center] = true;
        Node* root = new (allocate()) Node(-RANGE, RANGE);
        static std::vector<Data> datas[LARGE + 1];
        //正向两条路径
        for (int _i = 0; _i < graph[center].size(); _i += 1) {
            int to = graph[center][_i];
            if (removed[to] == false) {
                std::vector<Data>& curr = datas[_i];
                curr.clear();
                DFS1(to, -1, 1, curr, INF, true);
                for (int i = 0; i < curr.size(); i++) {
                    //两条路径
                    const Data& thiz = curr[i];
                    //以分治中心为一个端点的答案
                    result = std::max(result, std::min((int_t)curr[i].val,
                                                       (int_t)::vals[center]) *
                                                  (curr[i].depth + 1));
                    result = std::max(
                        result,
                        ((int_t)root->query(thiz.val, RANGE) + thiz.depth) * thiz.val);
                }
                for (int i = 0; i < curr.size(); i++) {
                    //加入答案
                    const Data& thiz = curr[i];
                    root->maxTo(std::min(thiz.val, ::vals[center]),
                                thiz.depth + 1);
                }
            }
        }
        //反向两条路径
        used = 0;
        root = new (allocate()) Node(-RANGE, RANGE);
        for (int _i = graph[center].size() - 1; _i >= 0; _i -= 1) {
            int to = graph[center][_i];
            if (removed[to] == false) {
                std::vector<Data>& curr = datas[_i];
                for (int i = 0; i < curr.size(); i++) {
                    //两条路径
                    const Data& thiz = curr[i];
                    result = std::max(
                        result,
                        ((int_t)root->query(thiz.val, RANGE) + thiz.depth) * thiz.val);
                }
                for (int i = 0; i < curr.size(); i++) {
                    //加入答案
                    const Data& thiz = curr[i];
                    root->maxTo(std::min(thiz.val,::vals[center]),
                                thiz.depth + 1);
                }
            }
        }
        //子树信息
        for (int i = 0; i < graph[center].size(); i++) {
            int to = graph[center][i];
            if (removed[to] == false) {
                result = std::max(result, DFS3(to));
            }
        }
        used = 0;
        removed[center] = false;
        return result;
    }
    int main() {
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) {
            scanf("%d", &vals[i]);
        }
        for (int i = 1; i <= n - 1; i++) {
            int v1, v2;
            scanf("%d%d", &v1, &v2);
            graph[v1].push_back(v2);
            graph[v2].push_back(v1);
        }
        printf("%lld", DFS3(1));
        return 0;
    }

     

  • Luogu4930 采药人的路径

    又犯了sb错误..

    求重心求错了。

    因为没写size[vtx]=1导致求出来的size全是0.

    #include <algorithm>
    #include <cassert>
    #include <cstdio>
    #include <iostream>
    #include <map>
    #include <set>
    #include <unordered_map>
    #include <vector>
    using std::cin;
    using std::cout;
    using std::endl;
    
    using int_t = long long int;
    const int_t LARGE = 1e5;
    const int_t INF = 0x7fffffff;
    struct Data {
        int_t dis;
        //当前路径是否存在0
        bool zero;
    };
    struct Edge {
        int_t to, weight;
    };
    int n;
    bool removed[LARGE + 1];
    int_t size[LARGE + 1];
    int_t _data[LARGE * 2 + 1];
    int_t* vals = _data + LARGE;
    std::vector<Edge> graph[LARGE + 1];
    
    void pushEdge(int_t from, int_t to, int_t weight) {
        graph[from].push_back(Edge{to, weight});
        graph[to].push_back(Edge{from, weight});
    }
    void DFS1(int_t vtx, std::vector<Data>& result, bool saving = false,
              int_t dis = 0, int_t from = -1) {
        //忘了初始化size导致size算出来全是0
        size[vtx] = 1;
        if (saving) {
            if (vals[dis])
                result.push_back(Data{dis, true});
            else
                result.push_back(Data{dis, false});
        }
        vals[dis]++;
        for (const auto& edge : graph[vtx]) {
            if (edge.to != from && removed[edge.to] == false) {
                DFS1(edge.to, result, saving, dis + edge.weight, vtx);
                size[vtx] += size[edge.to];
            }
        }
        vals[dis]--;
    }
    void DFS2(int_t vtx, int_t& center, int_t& size, int_t rootSize = -1,
              int_t from = -1) {
        int_t maxSize = 0;
        if (from == -1) {
            rootSize = ::size[vtx];
        }
        for (const auto& edge : graph[vtx]) {
            if (edge.to != from && removed[edge.to] == false) {
                maxSize = std::max(maxSize, ::size[edge.to]);
                DFS2(edge.to, center, size, rootSize, vtx);
            }
        }
        maxSize = std::max(maxSize, rootSize - ::size[vtx]);
        if (maxSize < size) {
            size = maxSize;
            center = vtx;
        }
    }
    int_t DFS3(int_t vtx) {
        static std::vector<Data> _;
        DFS1(vtx, _, false);
        int_t center, size = INF;
        DFS2(vtx, center, size);
        removed[center] = true;
        int_t result = 0;
    
        std::unordered_map<int_t, int_t> datas[2];
    //不要把center写成vtx!!
        for (const auto& edge : graph[center]) {
            if (removed[edge.to] == false) {
                std::vector<Data> curr;
                DFS1(edge.to, curr, true);
                //统计以重心为端点的答案
                for (auto& data : curr) {
                    if (data.dis + edge.weight == 0 && data.zero) result++;
                    //统计来自两棵不同子树的答案
                    data.zero |= (data.dis + edge.weight == 0);
                    data.dis += edge.weight;
                    int_t res = -data.dis;
                    result += datas[1][res];
                    if (data.zero) result += datas[0][res];
                }
                for (const auto& data : curr) {
                    datas[data.zero][data.dis]++;
                }
            }
        }
        for (const auto& edge : graph[center]) {
            if (removed[edge.to] == false) {
                result += DFS3(edge.to);
            }
        }
        removed[center] = false;
        return result;
    }
    int main() {
        scanf("%d", &n);
        for (int i = 1; i <= n - 1; i++) {
            int from, to, weight;
            scanf("%d%d%d", &from, &to, &weight);
            if (weight == 0) weight = -1;
            pushEdge(from, to, weight);
        }
        cout << DFS3(1) << endl;
        return 0;
    }

     

  • Luogu4149 IOI2011 Race

    点分治板子。

    记录一下每条路径的深度即可。

    #include <algorithm>
    #include <iostream>
    #include <map>
    #include <vector>
    using std::cin;
    using std::cout;
    using std::endl;
    
    using int_t = long long int;
    const int_t LARGE = 2e5;
    const int_t INF = 0x7fffffff;
    struct Data {
        int_t dis, depth;
    };
    struct Edge {
        int_t to, weight;
    };
    bool removed[LARGE + 1];
    int_t size[LARGE + 1];
    std::vector<Edge> graph[LARGE + 1];
    
    void pushEdge(int_t from, int_t to, int_t weight) {
        graph[from].push_back(Edge{to, weight});
        graph[to].push_back(Edge{from, weight});
    }
    void DFS1(int_t vtx, std::vector<Data>& result, int_t depth = 0, int_t dis = 0,
              int_t from = -1) {
        size[vtx] = 1;
        result.push_back(Data{dis, depth});
        for (const auto& edge : graph[vtx]) {
            if (edge.to != from && removed[edge.to] == false) {
                DFS1(edge.to, result, depth + 1, dis + edge.weight, vtx);
                size[vtx] += size[edge.to];
            }
        }
    }
    void DFS2(int_t vtx, int_t& center, int_t& size, int_t rootSize = -1,
              int_t from = -1) {
        int_t maxSize = 0;
        if (from == -1) {
            rootSize = ::size[vtx];
            size = INF;
        }
        for (const auto& edge : graph[vtx]) {
            if (edge.to != from && removed[edge.to] == false) {
                maxSize = std::max(maxSize, ::size[edge.to]);
                DFS2(edge.to, center, size, rootSize, vtx);
            }
        }
        maxSize = std::max(maxSize, rootSize - ::size[vtx]);
        if (maxSize < size) {
            size = maxSize;
            center = vtx;
        }
    }
    int_t DFS3(int_t vtx, int_t k) {
        std::vector<Data> _;
        DFS1(vtx, _);
        _.resize(0);
        _.shrink_to_fit();
        int_t center, size;
        DFS2(vtx, center, size);
        removed[center] = true;
        int_t result = INF;
        std::map<int_t, int_t> datas;
    #ifdef DEBUG
        cout << "processing center " << center << " size " << size << " block "
             << vtx << endl;
    #endif
        //不要把center写成vtx!!
        for (const auto& edge : graph[center]) {
            if (removed[edge.to] == false) {
                std::vector<Data> curr;
                DFS1(edge.to, curr);
    #ifdef DEBUG
                cout << "center " << center << " chd " << edge.to << " ";
                for (auto x : curr) cout << x.dis << "," << x.depth << "  ";
                cout << endl;
    #endif
                //统计以重心为端点的答案
                for (const auto& data : curr) {
                    if (data.dis + edge.weight == k)
                        result = std::min(result, data.depth + 1);
                    int_t res = k - (data.dis + edge.weight);
                    //统计来自两棵不同子树的答案
                    if (datas.count(res))
                        result = std::min(result, datas[res] + data.depth + 1);
                }
                for (const auto& data : curr) {
                    int_t dis = data.dis + edge.weight;
                    if (datas.count(dis) == false)
                        datas[dis] = data.depth + 1;
                    else
                        datas[dis] = std::min(datas[dis], data.depth + 1);
                }
                result = std::min(result, DFS3(edge.to, k));
            }
        }
        removed[center] = false;
        return result;
    }
    int main() {
        int n, k;
        scanf("%d%d", &n, &k);
        for (int i = 1; i <= n - 1; i++) {
            int from, to, weight;
            scanf("%d%d%d", &from, &to, &weight);
            pushEdge(from, to, weight);
        }
        // int_t center, size;
        // std::vector<Data> x;
        // DFS1(4, x);
        // DFS2(4, center, size);
        // cout << "center = " << center << ",size=" << size << endl;
        int_t result = DFS3(0, k);
        if (result < INF)
            cout << result << endl;
        else
            cout << -1 << endl;
        // cout <<  << endl;
        return 0;
    }

     

  • Luogu 2634 聪聪可可

    又是一道点分治板子..

    #include <iostream>
    #include <map>
    #include <vector>
    using int_t = long long int;
    using std::cin;
    using std::cout;
    using std::endl;
    
    const int_t LARGE = 2e4;
    const int_t INF = 0x7fffffff;
    
    struct Edge {
        int_t to, weight;
    };
    
    bool removed[LARGE + 1];
    int_t size[LARGE + 1];
    
    std::vector<Edge> graph[LARGE + 1];
    void pushEdge(int_t from, int_t to, int_t weight) {
        graph[from].push_back(Edge{to, weight});
        graph[to].push_back(Edge{from, weight});
    }
    //统计vec中距离和为k的无序对数量
    int_t count(const std::vector<int_t>& vec, int_t offset = 0) {
        int_t mods[3] = {0, 0, 0};
        const auto C2 = [&](int_t x) -> int_t { return x * (x - 1) / 2; };
        for (int_t x : vec) {
            mods[((x + offset) % 3 + 3) % 3]++;
        }
        return C2(mods[0]) + mods[1] * mods[2];
    }
    //求子树大小和各节点深度
    void DFS0(int_t vtx, std::vector<int_t>& result, int_t depth = 0,
              int_t from = -1) {
        size[vtx] = 1;
        result.push_back(depth);
        for (const auto& edge : graph[vtx]) {
            if (edge.to != from && removed[edge.to] == false) {
                DFS0(edge.to, result, depth + edge.weight, vtx);
                size[vtx] += size[edge.to];
            }
        }
    }
    //求重心
    void DFS1(int_t vtx, int_t& result, int_t& rSize, int_t rootSize = -1,
              int_t from = -1) {
        int_t maxSize = 0;
        if (from == -1) rootSize = size[vtx];
        for (const auto& edge : graph[vtx]) {
            if (edge.to != from && removed[edge.to] == false) {
                maxSize = std::max(maxSize, size[edge.to]);
                DFS1(edge.to, result, rSize, rootSize, vtx);
            }
        }
        maxSize = std::max(maxSize, rootSize - size[vtx]);
        if (maxSize < rSize) {
            rSize = maxSize;
            result = vtx;
        }
    }
    //分治主过程
    int_t DFS3(int_t vtx) {
        int_t result = 0;
        //找重心
        int_t center = 0, size = INF;
        std::vector<int_t> depths;
        DFS0(vtx, depths);
        DFS1(vtx, center, size);
        depths.resize(0);
        removed[center] = true;
        for (const auto& edge : graph[center]) {
            if (removed[edge.to] == false) {
                //去除掉各棵子树内的答案
                std::vector<int_t> curr;
                DFS0(edge.to, curr);
                result -= count(curr, edge.weight);
                for (int_t x : curr) depths.push_back(x + edge.weight);
                result += DFS3(edge.to);
            }
        }
        //统计以重心为一个端点的答案
        for (int_t x : depths) result += (x % 3 == 0);
        //统计经过重心的答案
        result += count(depths);
        removed[center] = false;
        return result;
    }
    int_t gcd(int_t a, int_t b) {
        if (b == 0) return a;
        return gcd(b, a % b);
    }
    int main() {
        int_t n, m;
        cin >> n;
        for (int_t i = 1; i <= n - 1; i++) {
            int_t from, to, weight;
            cin >> from >> to >> weight;
            pushEdge(from, to, weight);
        }
        int_t a = DFS3(1) * 2 + n;
        int_t b = n * n;
        int_t d = gcd(a, b);
        cout << (a / d) << "/" << (b / d) << endl;
    
        return 0;
    }

     

  • 洛谷3806 点分治

    第一次写点分治就这么A了…

    就是个板子

    #include <iostream>
    #include <map>
    #include <vector>
    using int_t = long long int;
    using std::cin;
    using std::cout;
    using std::endl;
    
    const int_t LARGE = 1e4;
    const int_t INF = 0x7fffffff;
    
    struct Edge {
        int_t to, weight;
    };
    
    bool removed[LARGE + 1];
    int_t size[LARGE + 1];
    
    std::vector<Edge> graph[LARGE + 1];
    void pushEdge(int_t from, int_t to, int_t weight) {
        graph[from].push_back(Edge{to, weight});
        graph[to].push_back(Edge{from, weight});
    }
    //统计vec中距离和为k的无序对数量
    int_t count(const std::vector<int_t>& vec, int_t k) {
        std::map<int_t, int_t> count;
        int_t result = 0;
        for (int_t x : vec) {
            if (count.count(k - x)) result += count[k - x];
            count[x] += 1;
        }
        return result;
    }
    //求子树大小和各节点深度
    void DFS0(int_t vtx, std::vector<int_t>& result, int_t depth = 0,
              int_t from = -1) {
        size[vtx] = 1;
        result.push_back(depth);
        for (const auto& edge : graph[vtx]) {
            if (edge.to != from && removed[edge.to] == false) {
                DFS0(edge.to, result, depth + edge.weight, vtx);
                size[vtx] += size[edge.to];
            }
        }
    }
    //求重心
    void DFS1(int_t vtx, int_t& result, int_t& rSize, int_t rootSize = -1,
              int_t from = -1) {
        int_t maxSize = 0;
        if (from == -1) rootSize = size[vtx];
        for (const auto& edge : graph[vtx]) {
            if (edge.to != from && removed[edge.to] == false) {
                maxSize = std::max(maxSize, size[edge.to]);
                DFS1(edge.to, result, rSize, rootSize, vtx);
            }
        }
        maxSize = std::max(maxSize, rootSize - size[vtx]);
        if (maxSize < rSize) {
            rSize = maxSize;
            result = vtx;
        }
    }
    //分治主过程
    int_t DFS3(int_t vtx, int_t k) {
        int_t result = 0;
        //找重心
        int_t center = 0, size = INF;
        std::vector<int_t> depths;
        DFS0(vtx, depths);
        DFS1(vtx, center, size);
        depths.resize(0);
        removed[center] = true;
        for (const auto& edge : graph[center]) {
            if (removed[edge.to] == false) {
                //去除掉各棵子树内的答案
                std::vector<int_t> curr;
                DFS0(edge.to, curr);
                result -= count(curr, k - 2 * edge.weight);
                for (int_t x : curr) depths.push_back(x + edge.weight);
                result += DFS3(edge.to, k);
            }
        }
        //统计以重心为一个端点的答案
        for (int_t x : depths) result += (x == k);
        //统计经过重心的答案
        result += count(depths, k);
        removed[center] = false;
        return result;
    }
    
    int main() {
        int_t n, m;
        cin >> n >> m;
        for (int_t i = 1; i <= n - 1; i++) {
            int_t from, to, weight;
            cin >> from >> to >> weight;
            pushEdge(from, to, weight);
        }
        for (int_t i = 1; i <= m; i++) {
            int_t x;
            cin >> x;
            int_t result = DFS3(1, x);
            if (result)
                cout << "AYE" << endl;
            else
                cout << "NAY" << endl;
        }
        return 0;
    }