bzoj 4154 [Ipsc2015]Generating Synergy

题目描述

简要题意:给定一棵以 $1$ 为根的 $n$ 个点的有根树,现在有 $m$ 次操作,操作有两种,第一种操作给定 $u,k,c$,将 $u$ 的子树内距离 $u$ 不超过 $k$ 的点染成 $c$;第二种操作给定 $u$,求 $u$ 的颜色

$n\le 10^5$

Solution

大概就是矩形赋值,单点查询,直接上 $KD~Tree$ 即可

时间复杂度 $O(n\sqrt n)$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include <iostream>
#include <algorithm>
#include <vector>
#define maxn 100010
using namespace std;

const int p = 1000000007;

int n, c, q;

struct Edge {
int to, next;
} e[maxn * 2]; int c1, head[maxn];
inline void add_edge(int u, int v) {
e[c1].to = v; e[c1].next = head[u]; head[u] = c1++;
}

int in[maxn], out[maxn], c2, dep[maxn];
void dfs(int u, int fa) {
in[u] = ++c2;
for (int i = head[u]; ~i; i = e[i].next) {
int v = e[i].to; if (v == fa) continue;
dep[v] = dep[u] + 1; dfs(v, u);
} out[u] = c2;
}

struct Point {
int x, y;

friend bool operator == (const Point &u, const Point &v) { return u.x == v.x && u.y == v.y; }
} a[maxn];
inline bool cmpx(const Point &u, const Point &v) {
if (u.x == v.x) return u.y < v.y;
return u.x < v.x;
}

inline bool cmpy(const Point &u, const Point &v) {
if (u.y == v.y) return u.x < v.x;
return u.y < v.y;
}

vector<bool(*)(const Point &u, const Point &v)> cmp;
void init_cmp() {
cmp.push_back(cmpx);
cmp.push_back(cmpy);
}

#define lc i << 1
#define rc i << 1 | 1
struct KDtree {
int xl, xr, yl, yr, v, tag;
Point p;
} T[maxn * 4];
inline void pushdown(int i) {
int &tag = T[i].tag; if (!tag) return ;
T[lc].tag = T[lc].v = tag;
T[rc].tag = T[rc].v = tag;
tag = 0;
}

void build(int i, int l, int r, int d) {
T[i].tag = 0;
if (l == r) return T[i] = { a[l].x, a[l].x, a[l].y, a[l].y, 1, 0, a[l] }, void();
int m = l + r >> 1; nth_element(a + l, a + m, a + r + 1, cmp[d]); T[i].p = a[m];
build(lc, l, m, d ^ 1); build(rc, m + 1, r, d ^ 1);
T[i].xl = min(T[lc].xl, T[rc].xl);
T[i].xr = max(T[lc].xr, T[rc].xr);
T[i].yl = min(T[lc].yl, T[rc].yl);
T[i].yr = max(T[lc].yr, T[rc].yr);
}

void update(int i, int xl, int xr, int yl, int yr, int v) {
if (max(T[i].xl, xl) > min(T[i].xr, xr) || max(T[i].yl, yl) > min(T[i].yr, yr)) return ;
if (xl <= T[i].xl && T[i].xr <= xr && yl <= T[i].yl && T[i].yr <= yr)
return T[i].v = T[i].tag = v, void();
pushdown(i);
update(lc, xl, xr, yl, yr, v); update(rc, xl, xr, yl, yr, v);
}

int query(int i, int l, int r, const Point &p, int d) {
if (l == r) return T[i].v;
int m = l + r >> 1; pushdown(i);
if (T[i].p == p || cmp[d](p, T[i].p))
return query(lc, l, m, p, d ^ 1);
else return query(rc, m + 1, r, p, d ^ 1);
}

void work() {
cin >> n >> c >> q; int ans = 0;
fill(head + 1, head + n + 1, -1);
c1 = c2 = 0;
for (int i = 2; i <= n; ++i) {
int x; cin >> x;
add_edge(x, i);
} dep[1] = 1; dfs(1, 0);
for (int i = 1; i <= n; ++i) a[i] = { in[i], dep[i] };
build(1, 1, n, 0);
for (int i = 1; i <= q; ++i) {
int c, x, y, v = 0; cin >> x >> y >> c;
if (!c) v = query(1, 1, n, { in[x], dep[x] }, 0);
else update(1, in[x], out[x], dep[x], dep[x] + y, c);
ans = (ans + 1ll * v * i) % p;
} cout << ans << "\n";
}

int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);

int T; cin >> T; init_cmp();
while (T--) work();
return 0;
}