原题链接
这显然是一道树据结构毒瘤卡常题
考虑用树剖
则原操作珂转换为:
- 在区间\([l, r]\)同时\(±1\)
- 询问区间\([l, r]\)内有多少数\(>0\)
然后发现不能线段树
珂以用分块
在每一块里搞一个关于值域的后缀和,即\(\text{cnt}_{\text{i,j}}\)表示在第\(\text i\)块里大于或等于\(\text j\)的个数。
这珂以利用后缀和预处理出来。
因为每一次只是\(±1\),所以每一次在\(\text{cnt}\)上修改是\(O(1)\)的
区间修改时,整个块打\(\text{lazy}\)标记,旁边的暴力修改。
区间查询时,整个块里询问有多少个数\(>-\text{lazy}_\text i\),旁边的暴力查询。
所以总时间复杂度\(O(n^{1.5}\log n)\)
贴一下代码(太卡常了):
// by H~$~C
#include <stdio.h>
static int _swaptmp;
#define swap(x, y) (_swaptmp = x, x = y, y = _swaptmp) // 卡常毒瘤
#ifndef LOCAL_JUDGE
static char _in_buf[100000], *_in_p1 = _in_buf, *_in_p2 = _in_buf;
#define gc (__builtin_expect(_in_p1 == _in_p2, 0) && (_in_p2 = (_in_p1 = _in_buf) + \
fread(_in_buf, 1, 100000, stdin), _in_p1 == _in_p2) ? -1 : *_in_p1++)
#else
#define gc getchar()
#endif
inline int read() {
register char ch = gc;
register int x = 0, flag = 0;
while ((ch < 48 || ch > 57) && ch != 45) ch = gc;
if (ch == 45) flag = 1, ch = gc;
while (ch > 47 && ch < 58) x = (x << 3) + (x << 1) + (ch ^ 48), ch = gc;
return flag ? -x : x;
} // 继续卡常
static const int Maxn = 100005;
int n, q, opt_type, lastans;
int a[Maxn], b[Maxn];
struct Edge {
int to, nxt;
} e[Maxn << 1];
int head[Maxn], tot_edge;
inline void add_edge(int u, int v) {
e[++tot_edge] = (Edge){v, head[u]};
head[u] = tot_edge;
}
int son[Maxn], sz[Maxn];
int par[Maxn], dep[Maxn];
int top[Maxn], ind[Maxn], indx;
void dfs1(int u, int parent, int depth) {
par[u] = parent;
dep[u] = depth;
sz[u] = 1;
for (register int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (v == parent) continue;
dfs1(v, u, depth + 1);
sz[u] += sz[v];
if (sz[son[u]] < sz[v])
son[u] = v;
}
}
void dfs2(int u, int topv) {
top[u] = topv;
ind[u] = ++indx;
a[indx] = b[u];
if (son[u]) dfs2(son[u], topv);
for (register int i = head[u]; i; i = e[i].nxt)
if (e[i].to != par[u] && e[i].to != son[u])
dfs2(e[i].to, e[i].to);
}
namespace BLOCK {
static const int BASE = ::Maxn;
static const int blk = 248; // 调参珂真好
static const int BLOCK_SIZE = ::Maxn / blk + 5;
int bl[Maxn];
int L[Maxn], R[Maxn];
int lazy[Maxn];
unsigned char suf[BLOCK_SIZE][Maxn << 1]; // 还是卡常
void build() {
register int i, j;
for (i = 1; i <= n; ++i) {
bl[i] = (i - 1) / blk + 1;
if (!L[bl[i]]) L[bl[i]] = i;
R[bl[i]] = i;
}
for (i = 1; i <= bl[n]; ++i) {
for (j = L[i]; j <= R[i]; ++j) {
suf[i][a[j] + BASE]++;
}
for (j = BASE * 2; j >= 0; --j) {
suf[i][j] += suf[i][j + 1];
}
}
}
inline void add(int b, int &x, int val) {
if (val == 1) {
++x;
++suf[b][x + BASE];
}
else {
--suf[b][x + BASE];
--x;
}
}
void modify(int l, int r, int val) {
int pl = bl[l], pr = bl[r];
register int i;
if (pl == pr) {
for (i = l; i <= r; ++i)
add(pl, a[i], val);
return ;
}
for (i = l; i <= R[pl]; ++i)
add(pl, a[i], val);
for (i = L[pr]; i <= r; ++i)
add(pr, a[i], val);
for (i = pl + 1; i < pr; ++i)
lazy[i] += val;
}
int query(int l, int r) {
int pl = bl[l], pr = bl[r];
int ans = 0;
register int i;
if (pl == pr) {
for (i = l; i <= r; ++i)
ans += (a[i] + lazy[pl] > 0);
return ans;
}
for (i = l; i <= R[pl]; ++i) {
ans += (a[i] + lazy[pl] > 0);
}
for (i = L[pr]; i <= r; ++i) {
ans += (a[i] + lazy[pr] > 0);
}
for (i = pl + 1; i < pr; ++i) {
ans += suf[i][BASE - lazy[i] + 1];
}
return ans;
}
}
inline void modify(int x, int y, int w) {
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) swap(x, y);
BLOCK::modify(ind[top[x]], ind[x], w);
x = par[top[x]];
}
if (dep[x] > dep[y]) swap(x, y);
BLOCK::modify(ind[x], ind[y], w);
}
inline int query(int x, int y) {
int res = 0;
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) swap(x, y);
res += BLOCK::query(ind[top[x]], ind[x]);
x = par[top[x]];
}
if (dep[x] > dep[y]) swap(x, y);
res += BLOCK::query(ind[x], ind[y]);
return res;
}
int main() {
register int i;
n = read(), q = read(), opt_type = read();
for (i = 1; i < n; ++i) {
int u = read(), v = read();
add_edge(u, v);
add_edge(v, u);
}
for (i = 1; i <= n; ++i) {
b[i] = read();
// 如果原数太大(>q)或太小(<-q),则符号不会改变
if (b[i] > 100002) b[i] = 100002;
if (b[i] < -100002) b[i] = -100002;
}
dfs1(1, 0, 1);
dfs2(1, 1);
BLOCK::build();
while (q--) {
int op = read();
int x = read(), y, w;
if (opt_type) x ^= lastans;
if (op == 1) {
y = read();
w = read();
if (opt_type) y ^= lastans;
modify(x, y, w);
}
else if (op == 2) {
y = read();
if (opt_type) y ^= lastans;
lastans = query(x, y);
printf("%d\n", lastans);
}
else {
lastans = BLOCK::query(ind[x], ind[x] + sz[x] - 1);
printf("%d\n", lastans);
}
}
return 0;
}