Description

给一棵nn个点的有标号无根树,你需要找到满足条件的路径uvu−v的条数。
我们称路径uvu-v满足条件当且仅当u,vu,v且路径uvu-v上不存在点对
(a,b)(a,b),a,ba,b满足gcd(a,b)=agcd(a,b)=a
注意:路径uvu−vvuv−u是同一条路径。

Input

第一行一个整数n105n\le10^5
接下来n1n−1行,每行两个用空格隔开的整数a,ba,b,表示边(a,b)(a,b)

Output

一行一个整数,代表要求的答案。

Sample Input

4
3 1
3 2
3 4

Sample Output

2
//只有路径232 − 3343 − 4满足条件

Solution

这个题的转换很有意思
我们考虑用总路径数-不合法的路径数来得到合法的路径数
那么现在问题就在于,如何求不合法的路径数
首先根据题意,枚举起点uu,可以通过枚举uu的倍数来得到一些不合法的路径,我们可以称之为“限制”,很容易得出:每一个不合法的路径必定至少包含一个“限制”
知道这个有什么用呢?
重头戏来了:
dfn[x]dfn[x]xx点的dfs序,cover[x]cover[x]xx子树中最大的dfs序
考虑不合法路径aba-b,假设aba-b包含路径uvu-vdfn[u]<dfn[v]dfn[u]<dfn[v]dfn[a]<dfn[b]dfn[a]<dfn[b]
分两种情况讨论:

  1. uuvv的一个祖先
  2. uu不是vv的祖先

对于第一种情况

这时候a,ba,bu,vu,v有怎样的关系呢?我们来看下面这张图
BZOJ5480: 路径的条数
这时我们发现,aa可以是gg子树外的任意一点,bb可以是vv子树内的任意一点,他们对应的dfs序关系为
dfn[a]<dfn[g]  and  dfn[v]dfn[b]cover[v]dfn[a]<dfn[g]\ \ and\ \ dfn[v]\le dfn[b] \le cover[v]
当然你可能会问:那如果我们先遍历图中gg的那棵子树,上面这个关系就不成立了!(注意我们的前提条件,aa的dfs序小于bb
没错,所以我们还要讨论把上图中把a,ba,b交换的情况,此时关系为
dfn[v]dfn[a]cover[v]  and  dfn[b]>cover[g]dfn[v]\le dfn[a] \le cover[v]\ \ and\ \ dfn[b] > cover[g]

对于第二种情况

这种情况相对较简单,还是先上图
BZOJ5480: 路径的条数
此时aauu子树中的任意一点,bbvv子树中的任意一点
所以对应的关系就是
dfn[u]dfn[a]cover[u]  and  dfn[v]dfn[b]cover[v]dfn[u]\le dfn[a] \le cover[u]\ \ and\ \ dfn[v]\le dfn[b]\le cover[v]

说了这么多,这有什么用啊?

考虑这样一个坐标系BZOJ5480: 路径的条数
这个坐标系的横轴是dfn[a]dfn[a],纵轴是dfn[b]dfn[b]
再看看上面我们列出的条件,dfn[a]dfn[a]对应一个横轴上的区间,dfn[b]dfn[b]对应一个纵轴上的区间
这不是矩形嘛!
大致乱画一下,其实一堆条件(关系)就成了下面这个东西
BZOJ5480: 路径的条数
这些矩形内的每一个整点(dfn[a],dfn[b])(dfn[a],dfn[b]),都是满足我们要求的东西,也就是不合法
而每一个dfs序对应唯一节点,这样我们计算这些矩形内的整点个数就能得到不合法的路径数
如何计算?线段树维护扫描线即可,只不过把求面积改成求矩形内点的个数,如果具体不清楚可以直接看代码,代码还算是比较简明的
最终统计答案,由于我们这样求出的路径是无向的,设求出的路径数为ansans
答案就是n(n1)2ans\frac{n*(n-1)}{2}-ans

复杂度:枚举u,vu,vO(nln(n))O(n*ln(n))的,线段树还要再乘个log(n)log(n),所以总复杂度应该是O(nln(n)log(n))O(n*ln(n)*log(n))

最后献上本人丑陋的代码,现在是2019年3月28日22:06:10,目前在BZOJ是最快的代码

/**************************************************************
    Problem: 5480
    User: Zechariah
    Language: C++
    Result: Accepted
    Time:13152 ms
    Memory:193400 kb
****************************************************************/
 
#include <bits/stdc++.h>
#define lowbit(x) (x & -x)
#define jh(x, y) x ^= y ^=x ^= y
#define loc(x, y) (x - 1) * m + y
#define rg register
#define inl inline
#define PI 3.141592654
typedef long long ll;
const int N = 8e5 + 5, mod = 998244353, INF = 0x3f3f3f3f;
using namespace std;
namespace fast_IO {
    inl ll read() {
        rg char c;
        rg ll x = 0;
        rg bool flag = false;
        while ((c = getchar()) == ' ' || c == '\n' || c == '\r');
        if (c == EOF)return c; if (c == '-')flag = true; else x = c ^ 48;
        while ((c = getchar()) != ' ' && c != '\n' && c != '\r'&&~c)
            x = (x << 1) + (x << 3) + (c ^ 48);
        if (flag)return -x; return x;
    }
    inl ll max(rg ll a, rg ll b) { if (a > b)return a; return b; }
    inl ll min(rg ll a, rg ll b) { if (a < b)return a; return b; }
    void write(rg ll x) { if (x < 0)putchar('-'), x = -x; if (x >= 10)write(x / 10); putchar(x % 10 ^ 48); }
}
int cover[N], dfn[N], nt[N], b[N], p[N], num, id, fa[N][18], deep[N], tot, n;
struct Node {
    int left, right, min;
    ll sum;
}tree[N << 2];
struct Line {
    int l, r, v, y;
    Line(rg int l = 0, rg int r = 0, rg int y = 0, rg int v = 0) :l(l), r(r), y(y), v(v) {}
    bool operator <(const rg Line &s)const { return y < s.y; }
}e[N << 2];
inl void add(rg int x, rg int y) {
    b[++num] = y, nt[num] = p[x], p[x] = num;
    b[++num] = x, nt[num] = p[y], p[y] = num;
}
inl bool is(rg int x, rg int y) { return dfn[x] <= dfn[y] && cover[x] >= cover[y]; }
void dfs(rg int x) {
    dfn[x] = ++id;
    for (rg int e= p[x]; e; e = nt[e]) {
        if (b[e] == fa[x][0])continue;
        fa[b[e]][0] = x; deep[b[e]] = deep[x] + 1; dfs(b[e]);
    }
    cover[x] = id;
}
void build(rg int x, rg int l, rg int r) {
    tree[x].left = l, tree[x].right = r;
    if (l == r)return;
    rg int mid = l + r >> 1;
    build(x << 1, l, mid); build(x << 1 | 1, mid + 1, r);
}
inl void pushup(rg int x) {
    if (tree[x].min)tree[x].sum = tree[x].right - tree[x].left + 1;
    else tree[x].sum = tree[x << 1].sum + tree[x << 1 | 1].sum;
}
void update(rg int x, rg int l, rg int r, rg ll data) {
    if (tree[x].left == l && tree[x].right == r) {
        tree[x].min += data;
        pushup(x);
        return;
    }
    rg int mid = tree[x].left + tree[x].right >> 1;
    if (r <= mid)update(x << 1, l, r, data);
    else if (l > mid)update(x << 1 | 1, l, r, data);
    else {
        update(x << 1, l, mid, data);
        update(x << 1 | 1, mid + 1, r, data);
    }
    pushup(x);
}
inl ll query() {
    sort(e + 1, e + tot + 1);
    rg ll ans = 0;
    for (rg int i = 1; i < tot; ++i) {
        update(1, e[i].l, e[i].r, e[i].v);
        ans += tree[1].sum * (e[i + 1].y - e[i].y);
    }
    return ans;
}
inl int getfa(rg int x, rg int d) {
    for (rg int j = 17; ~j; --j)
        if (d & (1 << j))
            x = fa[x][j];
    return x;
}
inl void addedge(rg int x1, rg int x2, rg int y1, rg int y2) {
    if (1 <= x1 && x1 <= x2 && x2 <= n && 1 <= y1 && y1 <= y2 && y2 <= n)
        e[++tot] = Line(x1, x2, y1, 1), e[++tot] = Line(x1, x2, y2 + 1, -1);
}
 
int main(void) {
    n = fast_IO::read();
    for (rg int i = 1; i != n; ++i)add(fast_IO::read(), fast_IO::read());
    dfs(1); build(1, 1, n);
    for (rg int j = 1; j != 18; ++j)
        for (rg int i = 1; i <= n; ++i)
            fa[i][j] = fa[fa[i][j - 1]][j - 1];
    for (rg int i = 1; i <= n; ++i) {
        for (rg int j = i << 1; j <= n; j += i) {
            rg int x = i, y = j;
            if (dfn[x] > dfn[y])jh(x, y);
            if (is(x, y)) {
                rg int node = getfa(y, deep[y] - deep[x] - 1);
                addedge(1, dfn[node] - 1, dfn[y], cover[y]);
                addedge(dfn[y], cover[y], cover[node] + 1, n);
            }
            else addedge(dfn[x], cover[x], dfn[y], cover[y]);
        }
    }
    fast_IO::write((ll)n * (n - 1) / 2 - query());
    return 0;
}


相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2021-12-24
  • 2022-01-24
  • 2021-06-06
  • 2021-05-08
  • 2022-12-23
  • 2021-04-13
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-09-14
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案