Codeforces Round #130 (Div. 2) E Blood Cousins
Blood Cousins
树上启发式合并 || \(dfs\) 序 + 二分
树上启发式合并就直接根据深度来合并起来就好了,答案就是问的那个点的 \(k\) 级祖先下,深度与问的那个点的儿子数量 - 1
对深度进行一个启发式合并就好了
好像还可以长链剖分?
注意该题是森林
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <array>
using namespace std;
const int maxn = 1e5 + 10;
#define pii pair<int, int>
int dep[maxn], L[maxn], rnk[maxn], R[maxn];
int hson[maxn], siz[maxn], fa[maxn];
int tp = 0, n, m, ans[maxn];
int cnt[maxn];
vector<int>gra[maxn];
vector<pii>qa[maxn], qb[maxn];
int st[maxn], stp = 0;
void dfs1(int now, int d)
{
dep[now] = d;
L[now] = ++tp;
rnk[tp] = now;
siz[now] = 1;
hson[now] = -1;
st[++stp] = now;
for(auto [x, y] : qa[now])
{
if(stp - x > 0)
qb[st[stp - x]].push_back({x, y});
}
for(int nex : gra[now])
{
if(nex == fa[now]) continue;
dfs1(nex, d + 1);
siz[now] += siz[nex];
if(hson[now] == -1 || siz[nex] > siz[hson[now]])
hson[now] = nex;
}
st[stp--] = 0;
R[now] = tp;
}
inline void add(int now)
{
cnt[dep[now]]++;
}
inline void del(int now)
{
cnt[dep[now]]--;
}
void dfs2(int now, bool keep)
{
for(int nex : gra[now])
if(nex != fa[now] && nex != hson[now]) dfs2(nex, false);
if(hson[now] != -1)
dfs2(hson[now], true);
for(int nex : gra[now])
{
if(nex != fa[now] && nex != hson[now])
{
for(int i=L[nex]; i<=R[nex]; i++)
{
add(rnk[i]);
}
}
}
add(now);
for(auto [x, y] : qb[now])
{
if(x + dep[now] <= n)
ans[y] = max(cnt[x + dep[now]] - 1, 0);
}
if(!keep)
{
for(int i=L[now]; i<=R[now]; i++)
del(rnk[i]);
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n;
for(int i=1; i<=n; i++)
{
cin >> fa[i];
if(fa[i])
gra[fa[i]].push_back(i);
}
cin >> m;
for(int i=0; i<m; i++)
{
int a, b;
cin >> a >> b;
qa[a].push_back({b, i});
}
for(int i=1; i<=n; i++)
{
if(fa[i] == 0)
{
dfs1(i, 1);
dfs2(i, false);
}
}
for(int i=0; i<m; i++)
cout << ans[i] << " ";
cout << "\n";
return 0;
}
\(dfs\) 序 + 二分
考虑其 \(dfs\) 序,按照深度为第一关键字,\(dfs\) 序为第二关键字,排序之后,找到对应深度的位置,通过 \(dfs\) 序,二分判断该深度子节点的数量
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <array>
using namespace std;
vector<int>dep, fa, L, R, ans, st;
int tp = 0;
vector<vector<int> >gra, de;
vector<vector<array<int, 2> > >qs;
void dfs(int now, int d)
{
dep[now] = d;
L[now] = ++tp;
st.push_back(now);
for(auto [x, i] : qs[now])
if((int)st.size() - x - 1 >= 0)
qs[st[(int)st.size() - 1 - x]].push_back({dep[now], i});
qs[now].clear();
de[dep[now]].push_back(tp);
for(int nex : gra[now])
{
if(nex == fa[now]) continue;
dfs(nex, d + 1);
}
R[now] = tp;
st.pop_back();
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
cin >> n;
L.resize(n + 1);
R.resize(n + 1);
dep.resize(n + 1);
fa.resize(n + 1);
gra.resize(n + 1);
de.resize(n + 1);
for(int i=1; i<=n; i++)
{
cin >> fa[i];
gra[fa[i]].push_back(i);
}
int m;
cin >> m;
qs.resize(n + 1);
ans.resize(m);
for(int i=0; i<m; i++)
{
int a, b;
cin >> a >> b;
qs[a].push_back({b, i});
}
for(int i=1; i<=n; i++) if(fa[i] == 0) dfs(i, 0);
for(int i=0; i<n; i++)
sort(de[i].begin(), de[i].end());
for(int i=1; i<=n; i++)
{
for(auto [d, id] : qs[i])
{
ans[id] = upper_bound(de[d].begin(), de[d].end(), R[i]) - lower_bound(de[d].begin(), de[d].end(), L[i]) - 1;
}
}
for(int i=0; i<m; i++)
{
if(i) cout << " ";
cout << ans[i];
}
cout << endl;
return 0;
}

浙公网安备 33010602011771号