P4216 [SCOI2015]情报传递 树剖+主席树
Posted kaka0010
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P4216 [SCOI2015]情报传递 树剖+主席树相关的知识,希望对你有一定的参考价值。
原题链接:https://www.luogu.com.cn/problem/P4216
题意
简单描述一下题意,有一棵树,m次操作
- 将x节点打上标记,并且x节点的权值每回合会增加1
- 询问x到y路径上有多少节点以及有多少节点权值大于c
分析
树上路径问题,一般直接想到树剖,然后考虑怎么去取值。先离线把打标记的时间记录一下,记为节点的权值,然后我们每次查询值的时候就只要查 [ 1 , t − v a l − 1 ] [1, t-val-1] [1,t−val−1]权值的点个数就可以了,可以用主席树轻松维护。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 10;
const int M = 1000010;
const int MOD = 1e9 + 7;
vector<int> g[N];
struct node {
int ls, rs, sum;
}hjt[N*50];
struct Query {
int k, x, y, c, t;
}q[N];
int rt[N], cnt, Rt, a[N], m;
int f[N][25];
void modify(int &now, int pre, int l, int r, int pos) {
now = ++cnt;
hjt[now] = hjt[pre];
hjt[now].sum ++;
if (l == r) return;
int mid = (l + r) >> 1;
if (pos <= mid) modify(hjt[now].ls, hjt[pre].ls, l, mid, pos);
else modify(hjt[now].rs, hjt[pre].rs, mid+1, r, pos);
}
int query(int u, int v, int lca, int fa_lca, int l, int r, int ql, int qr) {
if (ql <= l && qr >= r) return hjt[u].sum + hjt[v].sum - hjt[lca].sum - hjt[fa_lca].sum;
int mid = (l + r) >> 1;
int ans = 0;
if (ql <= mid) ans += query(hjt[u].ls, hjt[v].ls, hjt[lca].ls, hjt[fa_lca].ls, l, mid, ql, qr);
if (qr > mid) ans += query(hjt[u].rs, hjt[v].rs, hjt[lca].rs, hjt[fa_lca].rs, mid+1, r, ql, qr);
return ans;
}
int son[N], siz[N], dep[N], fat[N], dfn[N], rnk[N], top[N], tot;
void dfs1(int u, int fa) {
son[u] = -1; siz[u] = 1; dep[u] = dep[fa] + 1; fat[u] = fa;
f[u][0] = fa;
for (int i = 1; i <= 20; i++) f[u][i] = f[f[u][i-1]][i-1];
modify(rt[u], rt[fa], 0, m, a[u]);
for (auto v : g[u]) {
if (v == fa) continue;
dfs1(v, u);
siz[u] += siz[v];
if (son[u] == -1 || siz[v] > siz[son[u]]) son[u] = v;
}
}
void dfs2(int u, int t) {
rnk[dfn[u] = ++tot] = u; top[u] = t;
if (son[u] == -1) return;
dfs2(son[u], t);
for (auto v : g[u]) {
if (v != son[u] && v != fat[u]) dfs2(v, v);
}
}
int lca(int x, int y) {
if (dep[x] > dep[y]) swap(x, y);
for (int i = 20; i >= 0; i--) if (dep[y] - dep[x] >= (1 << i)) y = f[y][i];
if (x == y) return x;
for (int i = 20; i >= 0; i--) {
if (f[y][i] != f[x][i])
y = f[y][i], x = f[x][i];
}
return f[x][0];
}
void solve () {
int n; cin >> n;
for (int i = 1; i <= n; i++) {
int x; cin >> x;
if (!x) Rt = i;
else g[i].push_back(x), g[x].push_back(i);
}
cin >> m;
for (int i = 1; i <= n; i++) a[i] = m + 1;
for (int i = 1; i <= m; i++) {
cin >> q[i].k;
if (q[i].k == 1) {
cin >> q[i].x >> q[i].y >> q[i].c;
} else {
cin >> q[i].t;
a[q[i].t] = i;
}
}
dfs1(Rt, 0);
dfs2(Rt, Rt);
for (int i = 1; i <= m; i++) {
if (q[i].k == 1) {
int _lca = lca(q[i].x, q[i].y);
int fa_lca = f[_lca][0];
int num1 = dep[q[i].x] + dep[q[i].y] - 2*dep[_lca] + 1;
int num2 = query(rt[q[i].x], rt[q[i].y], rt[_lca], rt[fa_lca], 0, m, 0, max(0, i - q[i].c - 1));
cout << num1 << " " << num2 << endl;
}
}
}
signed main() {
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
#ifdef ACM_LOCAL
freopen("input", "r", stdin);
freopen("output", "w", stdout);
signed test_index_for_debug = 1;
char acm_local_for_debug = 0;
do {
if (acm_local_for_debug == '$') exit(0);
if (test_index_for_debug > 20)
throw runtime_error("Check the stdin!!!");
auto start_clock_for_debug = clock();
solve();
auto end_clock_for_debug = clock();
cout << "Test " << test_index_for_debug << " successful" << endl;
cerr << "Test " << test_index_for_debug++ << " Run Time: "
<< double(end_clock_for_debug - start_clock_for_debug) / CLOCKS_PER_SEC << "s" << endl;
cout << "--------------------------------------------------" << endl;
} while (cin >> acm_local_for_debug && cin.putback(acm_local_for_debug));
#else
solve();
#endif
return 0;
}
以上是关于P4216 [SCOI2015]情报传递 树剖+主席树的主要内容,如果未能解决你的问题,请参考以下文章