题目大意:
维护一棵初始有n个节点的有根树(根节点为1),树上节点编号为1-n,每个点有一个权值wi。
支持以下操作:
0 u x 询问以u为根的子树中,严格大于x的值的个数。(u^=lastans,x^=lastans)
1 u x 把u节点的权值改成x。(u^=lastans,x^=lastans)
2 u x 添加一个编号为"当前树中节点数+1"的节点,其父节点为u,其权值为x。(u^=lastans,x^=lastans)
最开始时lastans=0。
思路:开始看到询问是与子树有关的,又要支持动态加点,想到动态维护dfs序,然而一个区间第k大就让splay滚粗了。
然后离线构树也不行。
那么觉得不可做,想到分块乱搞。
然而这是一棵树,如何进行树上分块呢?
我们用一次dfs过程将树分块。
首先,定义根节点在块1中,块1的size为1.
从根节点向下dfs,对于当前点x,依次遍历其儿子,若遍历到儿子son时x所在的块的size小于Maxsize,则将son加入x所在的块,x所在的块的size+1.
否则,建立一个新块,使son加入这个新块,新块的size+1.
每遍历到一个儿子就向下dfs.
然后我们记录两个图,一个是原来的树,一个是块与块之间形成的图,只需要在每次产生新块的时候加一条边即可。
不难发现,块与块之间事实上形成的也是树形结构。
我们再对于每一个块记录下块内所有的权值,并排序。
对于询问,我们从当前节点向下dfs,若遇到一个儿子不属于其所在的块,则转到块与块之间形成的树向下搜索,每遇到一个块就在块里二分找答案。如果儿子依旧属于这个块,那就直接看一下他和x的大小关系即可。若令Maxsize=sqrt(n),这样的复杂度是O(sqrt(n)log(sqrt(n))).
对于加入新点,我们直接在其父亲所在的块中加入一个点即可,需要暴力修改权值的有序序列,复杂度O(sqrt(n)).当然如果父亲所在的块size达到了MAxsize,就新建一个一个点的新块。
如果修改权值,就直接在这个点所在的块的权值序列中暴力删除,插入即可,时间复杂度O(sqrt(n)).
事实上可能取Maxsize=sqrt(n)logn快一些?不过我T了。。。
Code:
#include <cmath>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
inline int getc() {
static const int L = 1 << 15;
static char buf[L], *S = buf, *T = buf;
if (S == T) {
T = (S = buf) + fread(buf, 1, L, stdin);
if (S == T)
return EOF;
}
return *S++;
}
inline int getint() {
int c;
while(!isdigit(c = getc()));
int tmp = c - '0';
while(isdigit(c = getc()))
tmp = (tmp << 1) + (tmp << 3) + c - '0';
return tmp;
}
#define N 30010
#define M 30010
#define Num 5010
#define Size 5010
struct Graph {
int head[N + M], next[(N + M)<<1], end[(N + M)<<1], ind;
void reset() {
ind = 0;
memset(head, -1, sizeof(head));
}
void addedge(int a, int b) {
int q = ind++;
end[q] = b;
next[q] = head[a];
head[a] = q;
}
void make(int a, int b) {
addedge(a, b);
addedge(b, a);
}
}G;
struct Lump {
int head[Num], next[Num << 1], end[Num << 1], ind;
void reset() {
ind = 0;
memset(head, -1, sizeof(head));
}
void addedge(int a, int b) {
int q = ind++;
end[q] = b;
next[q] = head[a];
head[a] = q;
}
void make(int a, int b) {
addedge(a, b);
addedge(b, a);
}
}Lumps;
int w[N + M];
int per, size[Num], sav[Num][Size], belong[N + M], cnt, pa[N + M];
void dfs(int x, int fa) {
for(int j = G.head[x]; j != -1; j = G.next[j]) {
if (G.end[j] == fa)
continue;
pa[G.end[j]] = x;
if (size[belong[x]] == per) {
belong[G.end[j]] = ++cnt, sav[cnt][++size[cnt]] = w[G.end[j]];
Lumps.make(cnt, belong[x]);
}
else
belong[G.end[j]] = belong[x], sav[belong[x]][++size[belong[x]]] = w[G.end[j]];
dfs(G.end[j], x);
}
}
inline int ask_Big(int ins, int x) {
sav[ins][size[ins] + 1] = 1 << 30;
int L = 1, R = size[ins] + 1, mid;
while(L < R) {
mid = (L + R) >> 1;
if (sav[ins][mid] > x)
R = mid;
else
L = mid + 1;
}
return size[ins] + 1 - L;
}
inline int ask_Lump(int x, int fa, int val) {
int res = ask_Big(x, val);
for(int j = Lumps.head[x]; j != -1; j = Lumps.next[j]) {
if (Lumps.end[j] != fa)
res += ask_Lump(Lumps.end[j], x, val);
}
return res;
}
inline int ask(int x, int fa, int val) {
int res = w[x] > val ? 1 : 0;
for(int j = G.head[x]; j != -1; j = G.next[j]) {
if (G.end[j] != fa) {
if (belong[G.end[j]] != belong[x])
res += ask_Lump(belong[G.end[j]], belong[x], val);
else
res += ask(G.end[j], x, val);
}
}
return res;
}
void remove(int ins, int val) {
int i, j;
for(i = 1; i <= size[ins]; ++i)
if (sav[ins][i] == val)
break;
--size[ins];
for(j = i; j <= size[ins]; ++j)
sav[ins][j] = sav[ins][j + 1];
}
void insert(int ins, int val) {
int i, j;
for(i = 1; i <= size[ins]; ++i)
if (sav[ins][i] > val)
break;
++size[ins];
for(j = size[ins]; j > i; --j)
sav[ins][j] = sav[ins][j - 1];
sav[ins][i] = val;
}
int main() {
int n = getint();
register int i;
int a, b;
G.reset();
for(i = 1; i < n; ++i) {
a = getint(), b = getint();
G.make(a, b);
}
for(i = 1; i <= n; ++i)
w[i] = getint();
per = (int)sqrt(n * log(n)/log(2));
Lumps.reset();
belong[1] = size[++cnt] = 1, sav[cnt][1] = w[1];
dfs(1, -1);
for(i = 1; i <= cnt; ++i)
sort(sav[i] + 1, sav[i] + size[i] + 1);
int Q, ope, lastans = 0;
Q = getint();
while(Q--) {
ope = getint(), a = getint(), b = getint();
a ^= lastans;
b ^= lastans;
if (!ope)
printf("%d\n", lastans = ask(a, pa[a], b));
else if (ope == 1) {
remove(belong[a], w[a]);
insert(belong[a], w[a] = b);
}
else {
w[++n] = b;
pa[n] = a;
if (size[belong[a]] == per) {
belong[n] = ++cnt;
size[cnt] = 1;
sav[cnt][1] = w[n];
G.make(a, n);
Lumps.make(belong[a], cnt);
}
else {
belong[n] = belong[a];
insert(belong[a], w[n]);
G.make(a, n);
}
}
}
return 0;
}