【题目大意】

给出一棵树,求有多少对点(u,v)满足其路径上不存在两个点a,b满足(a,b)=1

n<=10^5

【题解】

考虑找出所有不符合的点对,共有n*ln(n)对,他们要么是祖先->儿子边,要么是不是。

考虑祖先->儿子边,那么一个点在祖先以上,一个点在儿子以下的点对全部无法访问。

考虑另外一种边,就是LCA不是两个端点的,这就比较好统计了,两个点在这两棵子树的点对无法访问。

考虑用DFS序,这样子树就是连续的一段(祖先以上是连续两段)

然后就是一个二维覆盖问题,用扫描线+线段树即可解决。

复杂度O(nln(n)logn)

注意。。扫描线数组要开到 4 * n * ln(n) 不然。。会奇怪的WA/RE。。。

# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm> using namespace std; typedef long long ll;
typedef unsigned long long ull;
typedef long double ld; # define RG register
# define ST static const int M = 2e5 + , N = 1e5 + , Max = * M;
const int mod = ; int n, head[N], nxt[M], to[M], tot = ;
inline void add(int u, int v) {
++tot; nxt[tot] = head[u]; head[u] = tot; to[tot] = v;
}
inline void adde(int u, int v) {
add(u, v), add(v, u);
} int in[N], out[N], DFN = ;
int dep[N], fa[N][];
inline void dfs(int x, int fat = ) {
in[x] = ++DFN; dep[x] = dep[fat] + ;
fa[x][] = fat;
for (int i=; i<=; ++i) fa[x][i] = fa[fa[x][i-]][i-];
for (int i=head[x]; i; i=nxt[i]) {
if(to[i] == fat) continue;
dfs(to[i], x);
}
out[x] = DFN;
} inline int lca(int u, int v) {
if(dep[u] < dep[v]) swap(u, v);
for (int i=; ~i; --i)
if((dep[u] - dep[v]) & (<<i)) u = fa[u][i];
if(u == v) return u;
for (int i=; ~i; --i)
if(fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i];
return fa[u][];
} inline int jump(int u, int anc) {
for (int i=; ~i; --i)
if(dep[fa[u][i]] > dep[anc]) u = fa[u][i];
return u;
} struct pa {
int x, yl, yr, d;
pa() {}
pa(int x, int yl, int yr, int d) : x(x), yl(yl), yr(yr), d(d) {}
friend bool operator < (pa a, pa b) {
return a.x < b.x;
}
}p[Max * ]; int pn = ; inline void ADD(int xl, int xr, int yl, int yr) {
p[++pn] = pa(xl, yl, yr, );
p[++pn] = pa(xr+, yl, yr, -);
} inline void doit(int x, int y) {
int par = lca(x, y);
// if(par == -1) cout << x << ' ' << y << endl;
if(dep[x] > dep[y]) swap(x, y);
if(x == par) {
int pars = jump(y, par);
ADD(, in[pars] - , in[y], out[y]);
ADD(in[y], out[y], out[pars] + , n);
} else {
if(in[x] > in[y]) swap(x, y);
ADD(in[x], out[x], in[y], out[y]);
}
} struct SMT {
int w[Max], tag[Max];
# define ls (x<<)
# define rs (x<<|)
inline void set() {
memset(w, , sizeof w);
memset(tag, , sizeof tag);
}
inline int gs(int x, int l, int r) {
if(tag[x]) return r-l+;
else return w[x];
}
inline void edt(int x, int l, int r, int L, int R, int d) {
if(L > R) return ;
if(L <= l && r <= R) {tag[x] += d; return ;}
int mid = l+r>>;
if(L <= mid) edt(ls, l, mid, L, R, d);
if(R > mid) edt(rs, mid+, r, L, R, d);
w[x] = gs(ls, l, mid) + gs(rs, mid+, r);
}
inline int sum(int x, int l, int r, int L, int R) {
if(L > R) return ;
if(tag[x]) return min(R, r) - max(L, l) + ;
if(L <= l && r <= R) return gs(x, l, r);
int mid = l+r>>, ret = ;
if(L <= mid) ret += sum(ls, l, mid, L, R);
if(R > mid) ret += sum(rs, mid+, r, L, R);
return ret;
}
# undef ls
# undef rs
}T; int main() {
// freopen("A.in", "r", stdin);
// freopen("A.out", "w", stdout);
cin >> n;
for (int i=, u, v; i<n; ++i) {
scanf("%d%d", &u, &v);
adde(u, v);
}
dfs(, );
for (int i=; i<=n; ++i)
for (int j=i+i; j<=n; j+=i) doit(i, j); sort(p+, p+pn+); T.set();
ll ans = (ll)n * (n-) / ;
for (int i=, j=; i<=n; ++i) {
while(j<=pn && p[j].x == i) T.edt(, , n, p[j].yl, p[j].yr, p[j].d), ++j;
ans -= T.sum(, , n, i+, n);
}
cout << ans;
return ;
}

「6月雅礼集训 2017 Day2」A的更多相关文章

  1. 「6月雅礼集训 2017 Day2」C

    [题目大意] 有一棵n个点的完全二叉树,边权均为1,每个点有小鸟容量c[i] 依次来了m只小鸟,第i只小鸟初始位置在pos[i]上,问来了x只小鸟的时候,怎样安排小鸟的路线可以使得小鸟移动的边权和最小 ...

  2. 「6月雅礼集训 2017 Day2」B

    [题目大意] 求n*n的棋盘,每行每列都有2个黑格子的方案数. n<=10^7 [题解] zzq的做法好神奇啊 行列建点,二分图 左边有i个点,右边有j个点的方案数 f[i,j] 左边有i个点, ...

  3. 「6月雅礼集训 2017 Day10」quote

    [题目大意] 一个合法的引号序列是空串:如果引号序列合法,那么在两边加上同一个引号也合法:或是把两个合法的引号序列拼起来也是合法的. 求长度为$n$,字符集大小为$k$的合法引号序列的个数.多组数据. ...

  4. 「6月雅礼集训 2017 Day4」qyh(bzoj2687 交与并)

    原题传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2687 [题目大意] 给出若干区间,求一个区间的大于等于2的子集,使得 |区间并| 和 | ...

  5. 「6月雅礼集训 2017 Day11」delight

    [题目大意] 有$n$天,每天能吃饭.睡觉.什么事也不干 每天吃饭的愉悦值为$e_i$,睡觉的愉悦值为$s_i$,什么都不干愉悦值为0. 要求每连续$k$天都要有至少$E$天吃饭,$S$天睡觉. 求最 ...

  6. 「6月雅礼集训 2017 Day11」jump

    [题目大意] 有$n$个位置,每个位置有一个数$x_i$,代表从$i$经过1步可以到达的点在$[\max(1, i-x_i), \min(i+x_i, n)]$中. 定义$(i,j)$的距离表示从$i ...

  7. 「6月雅礼集训 2017 Day11」tree

    [题目大意] 给出一棵带权树,有两类点,一类黑点,一类白点. 求切断黑点和白点间路径的最小代价. $n \leq 10^5$ [题解] 直接最小割能过..但是树形dp明显更好写 设$f_{x,0/1/ ...

  8. 「6月雅礼集训 2017 Day10」perm(CodeForces 698F)

    [题目大意] 给出一个$n$个数的序列$\{a_n\}$,其中有些地方的数为0,要求你把这个序列填成一个1到$n$的排列,使得: $(a_i, a_j) = 1$,当且仅当$(i, j) = 1$.多 ...

  9. 「6月雅礼集训 2017 Day8」route

    [题目大意] 给出平面上$n$个点,求一条连接$n$个点的不相交的路径,使得转换的方向符合所给长度为$n-2$的字符串. $n \leq 5000$ [题解] 考虑取凸包上一点,然后如果下一个是‘R' ...

随机推荐

  1. Python的文件输入输出,如何追加内容,读取内容,添加内容

    python主要的文件打开的几种访问模式 模式可以为读模式('r').写模式('w')或追加模式('a'),当然还有rb.wb.ab.r+.w+.a+.rb+.wb+.ab+,然而实际从代码上我也没看 ...

  2. 序列化---fastjson使用

    该文章主要介绍com.alibaba.fastjson的使用. 首先创建maven工程,导入fastjson.挑个热度高的版本就好了. 首先考虑下,我们通常什么时候会使用序列化和反序列化: 1.将ja ...

  3. FlaskWeb开发从入门到放弃(二)

    第5章 章节五 01 内容概要 02 内容回顾 03 面向对象相关补充:metaclass(一) 04 面向对象相关补充:metaclass(二) 05 WTforms实例化流程分析(一) 06 WT ...

  4. cocos2d-x 精灵

    Sprite有两个父类:BatchableNode批量创建精灵(大量重复的比如子弹)和pyglet.sprite.Sprite. 精灵的创建

  5. P4332三叉神经树

    题面 \(Solution\) 通过模拟,我们会发现每次修改 \(x\),只会改变从 \(x\) 向上一段连续的链的输出. 例如将 \(x\) 点从 \(0\) 改为 \(1,\) 那么它会影响从它向 ...

  6. P2384洛谷 最短路

    题目描述 给定n个点的带权有向图,求从1到n的路径中边权之积最小的简单路径. 输入输出格式 输入格式: 第一行读入两个整数n,m,表示共n个点m条边. 接下来m行,每行三个正整数x,y,z,表示点x到 ...

  7. 一些排序算法的Python实现

    ''' Created on 2016/12/16 Created by freeol.cn 一些排序算法的Python实现 @author: 拽拽绅士 ''' '''值交换''' def swap( ...

  8. 条件随机场CRF

    条件随机场(CRF)是给定一组输入随机变量X的条件下另一组输出随机变量Y的条件概率分布模型,其特点是假设输出随机变量构成马尔科夫随机场.实际上是定义在时序数据上的对数线性模型.条件随机场属于判别模型. ...

  9. [boost-3] 函数对象

    boost库学习: 函数对象,成为‘高阶函数’,可以呗传入到其他函数或者从其他函数返回的一类函数. Boost.Bind可替换来自c++标准中的std::bind1st()和std::bind2dn( ...

  10. sql 条件插入

    原普通插入语句: insert into seriestable_upload values(New.SeriesID,0); 加条件后:(当不存在该条数据插入) insert into custom ...