題目大意:
維護一棵初始有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;
}