胡闹 多重集合问题

题目大意

维护一颗树,兹磁以下操作:

  1. 向以$v$为根的子树的所有节点各插入$k$个数$z$(相当于每个节点存了一些数)
  2. 询问某个节点$v$中有多少个数$x\ xor\ y\le z$,其中$y,z$是给出的
  3. 把整棵树的根换成某一个节点$v$

$n,m\le 140000$

解析

首先考虑查询

假设我们现在有一些数,然后查询有多少个异或上$y$不大于$z$

我们考虑把这些数建一个二进制的$Trie$。

考虑$z$的最高位,如果是$1$,那么就可以把$0$的$cnt$全部加进贡献。

如果是$0$,只能走到$0$。

这样每一位算一下就行。

接着考虑插入

对于一个子树的话,就用树链剖分的方法存$dfn$,然后映射出来就是一段区间。

这样的话直接$Trie$和线段树套一下就可以了。

最后考虑换根

换根的话,影响的只是子树的区间。

判一下根在不在区间内就可以了。

Code

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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#define  REP(i, s, e) for (int i = s ; i <= e; i++)
#define DREP(i, s, e) for (int i = s ; i >= e; i--)
#define DEBUG fprintf(stderr, "Passing [%s] in Line %d\n", __FUNCTION__, __LINE__)

#include <bits/stdc++.h>
#define int long long

using namespace std;
const int maxn = 140000 + 10, maxm = 140000 + 10;

int now = 1, root;
int bg[maxn], ne[maxn << 1], to[maxn << 1], e = 1;
void add(int x, int y)
{
e++;
to[e] = y;
ne[e] = bg[x];
bg[x] = e;
}
int fa[maxn], top[maxn], siz[maxn], depth[maxn], hvy[maxn];
int dfn[maxn], bac[maxn], dfs_clock;
void dfs1(int x)
{
siz[x] = 1;
for (int i = bg[x]; i ; i = ne[i])
if (to[i] ^ fa[x])
{
fa[to[i]] = x;
depth[to[i]] = depth[x] + 1;
dfs1(to[i]);
siz[x] += siz[to[i]];
if (siz[to[i]] > siz[hvy[x]]) hvy[x] = to[i];
}
}
void dfs2(int x, int y)
{
top[x] = y;
dfn[x] = ++dfs_clock;
if (hvy[x]) dfs2(hvy[x], y);
for (int i = bg[x]; i ; i = ne[i])
if (to[i] ^ hvy[x] && to[i] ^ fa[x]) dfs2(to[i], to[i]);
bac[x] = dfs_clock;
}
int find(int x, int y)
{
while (1)
{
if (top[x] == top[y]) return hvy[y];
if (fa[top[x]] == y) return top[x];
x = fa[top[x]];
}
}

struct node
{
int cnt;
node *ls, *rs;
}pool[55555555], *null, *node_cur = pool;
node* newnode()
{
node_cur -> ls = node_cur -> rs = null;
return node_cur++;
}
#define mid (l + r >> 1)
#define lson p -> ls, l, mid
#define rson p -> rs, mid + 1, r
void update(node *&p, int l, int r, int pos, int val)
{
if (p == null) p = newnode();
p -> cnt += val;
if (l == r) return;
if (pos <= mid) update(lson, pos, val);
else update(rson, pos, val);
}
int query(node *p, int l, int r, int pos)
{
if (p == null) return 0;
if (l == r) return p -> cnt;
if (pos > mid) return p -> ls -> cnt + query(rson, pos);
else return query(lson, pos);
}
struct Trie
{
node *t;
Trie *ch[2];
}t[4444444], *pt = t + 1;
int ans[maxm];

struct Query
{
int id, y, z, ne;
Query(){}
Query(int _id, int _y, int _z, int _ne) : id(_id), y(_y), z(_z), ne(_ne) {}
void query()
{
Trie* p = t;
DREP(i, 29, 0)
{
if (z >> i & 1)
if (p -> ch[((z^y)>>i&1) ^ 1]) ans[id] += ::query(p -> ch[((z^y)>>i&1) ^ 1] -> t, 1, now, id);
p = p -> ch[(z^y)>>i&1];
if (!p) return;
}
ans[id] += ::query(p -> t, 1, now, id);
}
}q[288888];
int pq = 144444;
void insert(int v, int id, int y, int z)
{
q[pq] = Query(id, y, z, q[v].ne);
q[v].ne = pq++;
}
struct opt
{
int t, k, x, v;
opt(){}
opt(int _t, int _k, int _x, int _v) : t(_t), k(_k), x(_x), v(_v) {}
void modify()
{
Trie* p = ::t;
DREP(l, 29, 0)
{
if (!p -> ch[x >> l & 1]) pt -> t = newnode(), p -> ch[x >> l & 1] = pt++;
p = p -> ch[x >> l & 1];
update(p -> t, 1, now, t, k);
}
}
bool operator < (opt B) const {return v < B.v;}
}op[433333];

int qcnt, Cur = 1;

int m, n;
signed main()
{
#ifndef ONLINE_JUDGE
freopen("B.in", "r", stdin);
freopen("B.out", "w", stdout);
#endif
cin >> n;
REP(i, 2, n)
{
int x, y;
scanf("%lld%lld", &x, &y);
add(x, y);add(y, x);
}
dfs1(1);
dfs2(1, 1);
null = pool + 55555500;
t -> t = newnode();
cin >> m;
REP(i, 1, m)
{
int Opt;scanf("%lld", &Opt);
if (Opt == 1)
{
int v, x, k;
scanf("%lld%lld%lld", &v, &x, &k);
if (dfn[v] >= dfn[root] || dfn[root] > bac[v])
if (v == root) op[++qcnt] = opt(now, k, x, 1);
else
{
op[++qcnt] = opt(now, k, x, dfn[v]);
op[++qcnt] = opt(now, -k, x, bac[v] + 1);
}
else
{
int temp = find(root, v);
op[++qcnt] = opt(now, k, x, 1);
op[++qcnt] = opt(now, -k, x, dfn[temp]);
op[++qcnt] = opt(now, k, x, bac[temp] + 1);
}
}
else if (Opt == 2)
{
int v, y, z;
scanf("%lld%lld%lld", &v, &y, &z);
insert(dfn[v], now++, y, z);
}
else scanf("%lld", &root);
}
sort(op + 1, op + qcnt + 1);
REP(i, 1, n)
{
while (op[Cur].v == i) op[Cur++].modify();
for (int p = q[i].ne; p ; p = q[p].ne)
q[p].query();
}
REP(i, 1, now - 1) printf("%lld\n", ans[i]);
return 0;
}

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×