题目大意
给定一个树,每个节点有个能量值代表可以往上跳的节点的个数。然后两种操作一个是查询结点跳出树的步数,一个是修改能量值
思路
可以对树进行分块。详细看代码注释
#include <map>
#include <set>
#include <cmath>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 100;
int n, head[maxn], to[maxn], nxt[maxn], tot;
void addEdge(int u, int v) {
to[tot]=v;nxt[tot]=head[u];head[u]=tot++;
}
int en[maxn], b, enl[maxn];
int fa[maxn][20], bel[maxn], top, st[maxn], cur;
int Next[maxn], ti[maxn];
/*分块操作*/
void dfs(int u) {
int ltop = top;
for(int i = head[u]; ~i; i = nxt[i]){
int v = to[i];
fa[v][0] = u;
dfs(v);
if(top - ltop >= b) {
cur++;
while(top > ltop) bel[st[--top]] = cur;
}
}
st[top++] = u;
}
/*倍增往上跳跳跳*/
int jump(int u, int lev) {
for(int i = 19; i >= 0; i--) {
if((1<<i) & lev) u = fa[u][i];
}
return u;
}
void update(int u) {
int s = enl[u];
if(bel[s] != bel[u]) { // ti[u]就是代表着跳出这个块所需的步骤
ti[u] = 1;
Next[u] = s;
}
else {
ti[u] = ti[s] + 1; // 在一个块中
Next[u] = Next[s];
}
}
vector<int> fbel[maxn];
void dfs0(int u) {
update(u);
fbel[bel[u]].push_back(u);
for(int i = head[u]; ~i;i=nxt[i]) {
dfs0(to[i]);
}
}
inline void init() {
b = (int)sqrt(0.4*n);
top=cur=0;
dfs(1); cur++;
while(top) bel[st[--top]] = cur;
/*初始化倍增*/
for(int j = 1; (1 << j) <= maxn; j++) {
for(int i = 1; i <= n; i++) {
fa[i][j]=fa[fa[i][j-1]][j-1];
}
}
// 算出每个点可以直接跳到的点
for(int i = 1; i <= n; i++) {
fbel[i].clear();
enl[i] = jump(i, en[i]);
}
// 自顶向下遍历
dfs0(1);
}
inline int query(int u) {
int ret = 0;
while(u) {
ret+=ti[u];
u = Next[u];
}
return ret;
}
char buf[(int)2e7];int idx=0;
void read(int & x) {
x=0;
for(;!isdigit(buf[idx]);++idx);
for(;isdigit(buf[idx]);++idx) x = x*10+buf[idx]-'0';
}
int main()
{
//freopen("/Users/maoxiangsun/MyRepertory/acm/code/i.txt", "r", stdin);
fread(buf,1,(int)2e7,stdin);
int T;
read(T);
while(T--) {
read(n);
memset(head,-1,sizeof(int) * (n + 1)); tot=0;
for(int i = 2; i <= n; i++) {
int u; read(u);
addEdge(u,i);
}
for(int i = 1; i <= n; i++) read(en[i]);
init();
int Q;
read(Q);
while(Q--) {
int op;
read(op);
if(op == 1) {
int u;read(u);
printf("%d\n", query(u));
}
else {
int x, y;
read(x);read(y);
en[x] = y;
enl[x] = jump(x,en[x]);
for(int i = 0; i < fbel[bel[x]].size(); i++) {
update(fbel[bel[x]][i]);
}
}
}
}
return 0;
}
/*
1
4
1 2 3
1 1 1 1
3
1 4
2 3 2
1 4
*/