zoukankan      html  css  js  c++  java
  • hiho1715 树的连通问题 动态开点线段树 + 线段树合并

    hiho1715 树的连通问题

    题目链接

    ​ 线段树 + 动态开点 + 线段树合并。

    ​ 暴力(O(n^2))。不可做。

    ​ 我们考虑问题转化,求每一条边的贡献,也就是有多少区间跨过这一条边。

    ​ 这么写不好写,正难则反,我们求这个问题的对偶问题,总区间数(-)有多少区间没有跨过这一条边。

    ​ 我们设当前点(x)的父亲为(fa),出现在(x)这颗子树里的点标为1,没有出现的标为0。(fa)也这么标记。

    ​ 总区间数很好算,(n * (n + 1) / 2),有多少区间没跨过这一条边就是这颗子树同为1的对数和同为0的对数。

    ​ 我们对每个节点搞一颗线段树,得用动态开点,(lmax1,rmax1,lmax0, rmax0)代表某一个区间紧靠左端(1)的个数,紧靠右端1的个数,紧靠左端0的个数,紧靠右端0的个数。(sum0, sum1)代表这个区间同为0的对数,同为1的对数。

    #include <bits/stdc++.h>
    
    #define mid ((l + r) >> 1)
    
    using namespace std;
    
    inline long long read() {
        long long s = 0, f = 1; char ch;
        while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
        for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
        return s * f;
    }
    
    const int N = 1e5 + 5;
    int n, cnt, tot;
    long long ans;
    int rt[N], head[N];
    struct edge { int to, nxt; } e[N << 1];
    struct tree { 
        int lc, rc;
        int lmax1, rmax1, lmax0, rmax0;
        long long sum0, sum1;
    } t[N << 4];
    
    void add(int x, int y) {
        e[++cnt].nxt = head[x]; head[x] = cnt; e[cnt].to = y; 
    }
    
    long long calc(int x) {
        return 1ll * (x + 1) * x / 2;
    }
    
    void modify(int o, int l, int r) {
        t[o].sum0 = calc(r - l + 1);
        t[o].lmax0 = t[o].rmax0 = r - l + 1;
    } 
    
    void up(int o, int l, int r) {
        if(!t[o].lc) modify(t[o].lc, l, mid);
        if(!t[o].rc) modify(t[o].rc, mid + 1, r);
        t[o].sum0 = t[t[o].lc].sum0 + t[t[o].rc].sum0 + 1ll * t[t[o].lc].rmax0 * t[t[o].rc].lmax0;
        t[o].sum1 = t[t[o].lc].sum1 + t[t[o].rc].sum1 + 1ll * t[t[o].lc].rmax1 * t[t[o].rc].lmax1;
        t[o].lmax0 = t[t[o].lc].lmax0 == mid - l + 1 ? t[t[o].lc].lmax0 + t[t[o].rc].lmax0 : t[t[o].lc].lmax0;
        t[o].lmax1 = t[t[o].lc].lmax1 == mid - l + 1 ? t[t[o].lc].lmax1 + t[t[o].rc].lmax1 : t[t[o].lc].lmax1;
        t[o].rmax0 = t[t[o].rc].rmax0 == r - mid ? t[t[o].rc].rmax0 + t[t[o].lc].rmax0 : t[t[o].rc].rmax0;
        t[o].rmax1 = t[t[o].rc].rmax1 == r - mid ? t[t[o].rc].rmax1 + t[t[o].lc].rmax1 : t[t[o].rc].rmax1;
    }
    
    void insert(int &o, int l, int r, int x) {
        if(!o) o = ++tot;
        if(l == r) { t[o].lmax1 = t[o].rmax1 = t[o].sum1 = 1; return ; }
        if(x <= mid) insert(t[o].lc, l, mid, x);
        if(x > mid) insert(t[o].rc, mid + 1, r, x);
        up(o, l, r);
    }
    
    int merge(int x, int y, int l, int r) {
        if(!x || !y) return x + y;
        if(l == r) return t[x].sum1 ? x : y;
        t[x].lc = merge(t[x].lc, t[y].lc, l, mid);
        t[x].rc = merge(t[x].rc, t[y].rc, mid + 1, r);
        up(x, l, r);
        return x;
    }
    
    void dfs(int x, int fa) {
        for(int i = head[x]; i ; i = e[i].nxt) {
            int y = e[i].to; if(y == fa) continue;
            dfs(y, x);
            rt[x] = merge(rt[x], rt[y], 1, n);
        }
        insert(rt[x], 1, n, x);
        if(x != 1) ans += calc(n) - t[rt[x]].sum0 - t[rt[x]].sum1;
    }
    
    int main() {
    
        n = read(); 
        for(int i = 1, x, y;i <= n - 1; i++) 
            x = read(), y = read(), add(x, y), add(y, x);
        dfs(1, 0);
        printf("%lld", ans);
    
        return 0;
    }
    
  • 相关阅读:
    SQLSTATE[HY000] [2054] The server requested authentication method unknown to the client
    Docker 下 nginx + tomcat 负债均衡
    Docker 安装 tomcat 并挂载宿主目录到容器
    Docker 安装 nginx 并挂载宿主目录到容器中
    SpringBoot 常见创建方式
    Java SPI 机制实现解耦
    TCP 粘包问题
    Docker 安装和常用命令
    Docker 安装 ActiveMQ
    INTEL
  • 原文地址:https://www.cnblogs.com/czhui666/p/13742873.html
Copyright © 2011-2022 走看看