题目描述
H
H
H国一共有
n
n
n座城市,编号为
1
1
1到
n
n
n的正整数。上个月
H
H
H国已经建成了一个通信网络,将这
n
n
n座城市通过
n
−
1
n-1
n−1条通信线路连接起来。为了保证所有城市之间都能互相通信,这
n
−
1
n-1
n−1跳通信线路组成一个树状的通信网络。显然,对于任意两个城市
x
x
x和
y
y
y,它们之间的同心路径是唯一。
现在,它们希望在此基础上建立一个应急的无线网络。每个城市
i
i
i都建有一个基站,海拔高度为
h
i
h_i
hi。当两个城市
x
x
x和
y
y
y需要通过无线网络通信时,他们会选择路径上的一个基站
z
z
z作为中继站(不包括
x
x
x和
y
y
y)。假如三个基站的海拔高度满足
h
x
+
h
y
≤
h
z
h_x+h_y\leq h_z
hx+hy≤hz,那么无线信号就能顺利转发,否则城市
x
x
x和
y
y
y就无法进行无线通信。
现在,已知通行网络的结构以及每个基站的海拔高度,请你求出一共有多少对城市之间能够进行无线通行。
输入格式
输入文件的第一行包含一个整数
n
n
n,表示城市数量。
接下来的
n
n
n行,每行包含两个正整数
f
i
f_i
fi和
h
i
h_i
hi。
其中
f
i
f_i
fi为
1
1
1到
i
−
1
i-1
i−1之间的正整数(特殊情况
f
i
=
0
f_i=0
fi=0),表示编号为
i
i
i的城市与标号为
f
i
f_i
fi的城市之间相连;
h
i
h_i
hi表示第
i
i
i个城市无线基站的海拔。
输出格式
输出文件共一行,包含一个非负整数,表示能够进行通信的城市对数。
样例输入
5
5
5
0
0
0
1
1
1
1
1
1
2
2
2
2
2
2
4
4
4
3
3
3
3
3
3
4
4
4
1
1
1
样例输出
3 3 3
数据范围
考试的时候最开始想到的是点分,头脑一热就直接打了“按点分序求满足
h
u
+
h
v
≤
h
r
t
h_u+h_v\leq h_{rt}
hu+hv≤hrt的路径数量”,而且还谜一般的过了样例。
然后一看题目,发现事情不对,好像要求的是点对数,显然按照点分序是不对的。
一看时间所剩无几,另外两题还没打过,匆匆改成了“按权值从大到小求满足
h
u
+
h
v
≤
h
r
t
h_u+h_v\leq h_{rt}
hu+hv≤hrt的路径数量”。
因为按照点权从大到小枚举,所以路径数量和点对数量是相等的。
时间复杂度
O
(
n
2
∗
log
n
)
O(n^2*\log n)
O(n2∗logn)
竟然还过了
50
%
50\%
50%的数据!!!
考完之后一看题解,嗯,好像只要把枚举的顺序倒过来,再用平衡树维护每个已经遍历过的点构成的连通块(以下简称连通块)内的信息就好了。
先证明一下平衡树合并的时空复杂度:
现在有两棵平衡树
T
1
T_1
T1和
T
2
T_2
T2,不妨设
T
1
.
s
i
z
e
≤
T
2
.
s
i
z
e
T_1.size\leq T_2.size
T1.size≤T2.size,那么将
T
1
T_1
T1中的每个元素暴力插入到
T
2
T_2
T2中,则新得到的
T
2
′
.
s
i
z
e
≥
2
∗
T
1.
s
i
z
e
T_2^{'}.size\geq2*T1.size
T2′.size≥2∗T1.size。
又因为最后的平衡树的大小是
O
(
n
)
O(n)
O(n)的,所以每个元素至多会被插入
O
(
n
∗
log
n
)
O(n*\log n)
O(n∗logn)次。
因为又懒又菜所以写了常数巨大,时间复杂度看脸的
T
r
e
a
p
Treap
Treap。
但即使像我这样最最丑
+
+
+暴力的写法,时间复杂度是
O
(
n
∗
log
2
n
)
O(n*\log^2n)
O(n∗log2n),空间复杂度是
O
(
n
∗
l
o
g
n
)
O(n*logn)
O(n∗logn)的 (据说时空复杂度都可以再少一个
l
o
g
log
log,然而本蒟蒻并不会)。
按照点权从小到大遍历,把各棵子树的信息都统计到
s
i
z
e
size
size最大的那颗平衡树中即可。
还有一个问题,我们遍历当前点
u
u
u所有未被访问过的相邻节点
v
v
v时,并不能保证编号为
v
v
v的平衡树就维护了
v
v
v所在连通块的信息。
而暴力去找最新的平衡树的编号时间复杂度就不能保证了,所以用并查集维护即可,祖先即为表示当前连通块内值域情况的平衡树编号。
总时间复杂度
O
(
n
∗
log
2
n
)
O(n*\log ^ 2 n)
O(n∗log2n)(并查集当成常数看了)。
C o d e Code Code
#include <queue>
#include <vector>
#include <cstdio>
#include <algorithm>
#define il inline
#define pb push_back
#define space putchar(' ')
#define enter putchar('\n')
using namespace std;
typedef long long ll;
template <typename T>
void read(T &x) {
x = 0;
bool f = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
f &= ch != '-', ch = getchar();
while (ch >= '0' && ch <= '9')
x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
x = f ? x : -x;
}
template <typename T>
void write(T x) {
if (x < 0)
x = -x, putchar('-');
if (x > 9)
write(x / 10);
putchar(x % 10 + 48);
}
const int maxn = 3e5 + 5;
const int maxe = 3e5 + 5;
const int maxt = 6e6 + 5;
int ed_cnt;
struct Edge {
int nxt, to;
} ed[maxe << 1];
int fir[maxn];
int w[maxn];
void clear_edge(int v_cnt) {
ed_cnt = 0;
for (int u = 1; u <= v_cnt; ++u)
fir[u] = 0;
}
il void add_edge(int u, int v) {
ed[++ed_cnt] = (Edge){ fir[u], v }, fir[u] = ed_cnt;
}
int id[maxn];
il bool cmp(const int &a, const int &b) {
return w[a] < w[b];
}
int t_cnt;
struct Tree {
int son[2], val, pri, cnt, siz;
} t[maxt];
class Treap {
private:
il void update(int p) {
t[p].siz = t[t[p].son[0]].siz + t[p].cnt + t[t[p].son[1]].siz;
}
void rotate(int &p, int d) {
int k = t[p].son[d];
t[p].son[d] = t[k].son[d ^ 1];
t[k].son[d ^ 1] = p;
update(p), update(p = k);
}
il int build(int val) {
t[++t_cnt] = (Tree){ { 0, 0 }, val, rand(), 1, 1 };
return t_cnt;
}
void _insert(int &p, int val) {
if (!p) {
p = build(val);
return;
}
t[p].siz++;
if (t[p].val == val) {
t[p].cnt++;
return;
}
int d = t[p].val < val;
_insert(t[p].son[d], val);
if (t[p].pri < t[t[p].son[d]].pri)
rotate(p, d);
}
int _lower(int p, int val) {
if (!p)
return 0;
if (t[p].val > val)
return _lower(t[p].son[0], val);
if (t[p].val == val)
return t[t[p].son[0]].siz + t[p].cnt;
return t[t[p].son[0]].siz + t[p].cnt + _lower(t[p].son[1], val);
}
public:
int rt;
Treap() {
rt = 0;
}
int siz() {
return t[rt].siz;
}
void insert(int val) {
_insert(rt, val);
}
int lower(int val) {
return _lower(rt, val);
}
} treap[maxn];
int fa[maxn];
int find(int x) {
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
bool vis[maxn];
int main() {
freopen("wireless.in", "r", stdin);
freopen("wireless.out", "w", stdout);
int n;
read(n);
clear_edge(n);
for (int u = 1; u <= n; ++u) {
int v;
read(v), read(w[u]);
if (v)
add_edge(u, v), add_edge(v, u);
}
for (int u = 1; u <= n; ++u)
id[u] = u;
sort(id + 1, id + n + 1, cmp);
for (int u = 1; u <= n; ++u)
fa[u] = u;
for (int u = 1; u <= n; ++u)
vis[u] = 0;
t_cnt = 0;
ll ans = 0;
for (int i = 1; i <= n; ++i) {
int u = id[i];
vis[u] = 1;
int mxs = 0, k = 0;
for (int e = fir[u]; e; e = ed[e].nxt) {
int v = ed[e].to;
if (!vis[v])
continue;
int x = find(v);
if (treap[x].siz() > mxs) {
mxs = treap[x].siz();
k = v;
}
}
if (k) {
treap[u].rt = treap[find(k)].rt;
for (int e = fir[u]; e; e = ed[e].nxt) {
int v = ed[e].to;
if(!vis[v] || v == k)
continue;
int x = find(v);
queue<int> q;
q.push(treap[x].rt);
vector<int> vec;
while (!q.empty()) {
int p = q.front();
q.pop();
vec.pb(p);
if (t[p].son[0])
q.push(t[p].son[0]);
if (t[p].son[1])
q.push(t[p].son[1]);
ans += treap[u].lower(w[u] - t[p].val) * t[p].cnt;
}
for (int i = 0, siz = vec.size(); i < siz; ++i)
for (int j = 1; j <= t[vec[i]].cnt; ++j)
treap[u].insert(t[vec[i]].val);
}
for (int e = fir[u]; e; e = ed[e].nxt) {
int v = ed[e].to;
if (!vis[v])
continue;
int x = find(v);
if (x != u)
fa[x] = u;
}
}
treap[u].insert(w[u]);
}
write(ans), enter;
return 0;
}