Tree
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 380 Accepted Submission(s): 130
Problem Description
Alice and Bob are playing with a magic tree This magic tree has n nodes,with n−1 magic paths connecting them into a connected block. Node 1 is at the top of the magic tree (layer 0). Node i is at the kth layer, where k is the distance from the node i to the node 1. Alice and Bob give a mana value on each node. If a magic stone falls on node i, it will be sent up to the k layer and appear on the kth ancestor node of the i layer(k is the mana value of node i). This node will continue to send up it, and so on. If the layer of node i is less than k, this stone will be sent out of the magic tree. Alice is curious, she will modify the magic value of a node, and ask Bob: If you drop a magic stone on the node x, how many times does it take to transfer it out of the magic tree?
Input
Input contains multiple tests
The first line contains one integer T(T≤4), indicating the number of test cases.
The following lines describe all the test cases
For each test case: The first line contains an integer n(n≤100000), indicating the size of the magic tree.
The second line has n−1 numbers, and the ith number represents the father of the node i+1.
The third row has n numbers, and the ith number represents the initial mana ai(ai≤n) value of each node.
In the fourth line, a number m(m≤100000) represents the number of operations.
The next m lines, one operation per line.
First a number op(1≤op≤2) represents the type of operation.
If op==1, a number x will be read immediately, indicating that a magic stone is thrown to the node x.
If op==2, it will immediately read in two numbers x and new_a, indicating that the magic value of node x is modified to new_a(new_a≤n).
Output
For each query with op==1, output the answer
Sample Input
1
4
1 2 3
1 1 1 1
3
1 4
2 3 2
1 4
Sample Output
4
3
题意:题意很明确, 就是给出一棵有根树, 然后每个点都有一个权值, 表示这个点可以传送到它的第a[i]个父亲节点上, 然后给出q个查询,每个查询有两种表示形式, 第一种:询问在x点经过几次传送可以传送出树(向上传送出根则表明传送出树) 第二种:将x点的权值更新为y
思路:有两种思路, 第一种是树分块, 第二种是LCT鉴于弱鸡不会LCT。。就只能说一下树分块的思路, 首先将树根据dfs序分块, 然后记录每个节点向上跳到下一个块所需要的次数, 然后再记录跳到下一个块中的那个点是多少, 对于第一种查询, 我们只需要按块暴力就行, 对于第二种修改, 我们也只需要修改与x处在同一个块里面, 且dfs序在x以下的点就可以了, 这样我们每次的复杂度都是块的大小, 或者块的个数, 这样复杂度基本可以过。 这里找父亲节点的时候要用倍增优化以下, 而且注意! 这里的块不要开根号n, 直接固定开100的大小就行了, 因为根号下1e5差不多是350, 这样的话如果每次都要修改或者查询的话是吃不消的, 不如直接开成100, 这样修改最大是100, 查询最大时1000, 这样复杂度怎么算都是差不多的。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
const int maxed = 100000 + 10;
struct E
{
int v, bef;
}e[maxed];
int n, m, ans, head[maxed], p[maxed];
int C[18], fa[maxed][18];
int block_size, block, size_[maxed], belong[maxed], cnt[maxed], id[maxed];
int main()
{
void add_(int x, int y);
void slove_1(int u);
void slove_2(int u, int cur);
for (int i = 0; i < 18; ++i)
C[i] = (1 << i);
int N;
scanf("%d", &N);
while (N--) {
ans = 1;
memset(head, -1, sizeof(head));
scanf("%d", &n);
int a;
for (int i = 1; i <= n - 1; ++i) {
scanf("%d", &a);
add_(a, i + 1);
}
for (int i = 1; i <= n; ++i)
scanf("%d", &p[i]);
block_size = 100;
memset(size_, 0, sizeof(size_));
block = 1;
belong[1] = 1, size_[1] = 1;
for (int i = 0; i < 18; ++i)
fa[1][0] = 0;
slove_1(1);
int b, c;
scanf("%d", &m);
while (m--) {
scanf("%d%d", &a, &b);
if (a == 1) {
int ans = 0, now = b;
while (true) {
ans += cnt[now];
now = id[now];
if (!now)
break;
}
printf("%d\n", ans);
}
else {
scanf("%d", &c);
p[b] = c;
slove_2(b, b);
}
}
}
return 0;
}
void add_(int x, int y)
{
e[ans].v = y;
e[ans].bef = head[x];
head[x] = ans++;
}
void slove_1(int u)
{
cnt[u] = 1, id[u] = 0;
int wa = u, w = p[u];
while (true) {
for (int i = 17; i >= 0; --i)
if (C[i] <= w) {
w -= C[i];
wa = fa[wa][i];
break;
}
if (!wa)
break;
if (!w) {
if (belong[u] == belong[wa]) {
//std::cout << u << "=====" << wa << "====" << cnt[wa] << std::endl;
cnt[u] += cnt[wa];
id[u] = id[wa];
}
else
id[u] = wa;
break;
}
}
for (int i = head[u]; i != -1; i = e[i].bef) {
int v = e[i].v;
if (size_[belong[u]] < block_size) {
size_[belong[u]] += 1;
belong[v] = belong[u];
}
else {
belong[v] = ++block;
size_[belong[v]] += 1;
}
fa[v][0] = u;
for (int j = 1; j < 18; ++j)
fa[v][j] = fa[fa[v][j - 1]][j - 1];
slove_1(v);
}
}
void slove_2(int u, int cur)
{
cnt[u] = 1, id[u] = 0;
int wa = u, w = p[u];
while (true) {
for (int i = 17; i >= 0; --i)
if (C[i] <= w) {
w -= C[i];
wa = fa[wa][i];
break;
}
if (!wa)
break;
if (!w) {
if (belong[u] == belong[wa]) {
cnt[u] += cnt[wa];
id[u] = id[wa];
}
else
id[u] = wa;
break;
}
}
for (int i = head[u]; i != -1; i = e[i].bef) {
int v = e[i].v;
if (belong[v] != belong[cur])
continue;
slove_2(v, cur);
}
}