ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

hiho1715 树的连通问题 动态开点线段树 + 线段树合并

2020-09-28 06:32:08  阅读:178  来源: 互联网

标签:rt 连通 ch hiho1715 int 线段 mid long


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;
}

标签:rt,连通,ch,hiho1715,int,线段,mid,long
来源: https://www.cnblogs.com/czhui666/p/13742873.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有