Oh,shit
树状数组 + 树链剖分,没什么好说的
直接用线段树会 TLE
#include <bits/stdc++.h>
#define N (1000000 + 10) /*------------------ #define ------------------*/
#define M (2000000 + 10)
#define MOD (1000000000 + 7)
//#define MOD (998244353)
#define INF (0x3f3f3f3f)
#define LNF (3e18)
#define mod(a,b) (((a)%(b)+(b))%(b))
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define fi first
#define se second
#define vvi vector<vector<int>>
#define vi vector<int>
#define vvl vector<vector<LL>>
#define vl vector<LL>
#define _vvi(n,m,k) vector<vector<int>>(n,vector<int>(m,k))
#define _vi(n,k) vector<int>(n,k)
#define _vvl(n,m,k) vector<vector<LL>>(n,vector<LL>(m,k))
#define _vl(n,k) vector<LL>(n,k)
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
typedef pair<LL,LL> PLL;
typedef pair<int,LL> PIL;
typedef pair<LL,int> PLI;
typedef pair<double,double> PDD;
// int n;
LL d[N];
vector<int> E[N];
/* 树链剖分 */
/*
完全不用知道实现原理,只用知道有啥用就可以了,有四个用途
(1)修改某条[u - v]路径上的所有节点的值,+k
(2)修改以 u 为根的子树上的所有节点的值,+k
(3)询问路径[u - v]上的所有节点的权值之和
(4)询问以 u 为根的子树上的所有节点的值的权值之和
本题中,我们用到了(1)、(2)、(3)
*/
int n, m;
int w[N], h[N], e[M], ne[M], idx;
int id[N], nw[N], cnt;
int dep[N], sz[N], top[N], fa[N], son[N];
/* BIT - 树状数组 */
int b[N];
// update
void update(int l,int r,int k){
for(int i = r;i <= n;i += i & -i)
b[i] += k;
}
// query
LL query(int x){
LL res = 0;
for(int i = x;i;i -= i & -i)
res += b[i];
return res;
}
LL query(int l,int r){
return query(r) - query(l - 1);
}
//init BIT
void init(int n){
for(int i = 1;i <= n;i ++ )
update(i,i,1);
}
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
void dfs1(int u, int father, int depth)
{
dep[u] = depth, fa[u] = father, sz[u] = 1;
for (int i = h[u]; ~i; i = ne[i])
{
int j = e[i];
if (j == father) continue;
dfs1(j, u, depth + 1);
sz[u] += sz[j];
if (sz[son[u]] < sz[j]) son[u] = j;
}
}
void dfs2(int u, int t)
{
id[u] = ++ cnt, nw[cnt] = w[u], top[u] = t;
if (!son[u]) return;
dfs2(son[u], t);
for (int i = h[u]; ~i; i = ne[i])
{
int j = e[i];
if (j == fa[u] || j == son[u]) continue;
dfs2(j, j);
}
}
void update_path(int u, int v, int k)
{
while (top[u] != top[v])
{
if (dep[top[u]] < dep[top[v]]) swap(u, v);
update(id[top[u]], id[u], k);
u = fa[top[u]];
}
if (dep[u] < dep[v]) swap(u, v);
update(id[v], id[u], k);
}
LL query_path(int u, int v)
{
LL res = 0;
while (top[u] != top[v])
{
if (dep[top[u]] < dep[top[v]]) swap(u, v);
res += query(id[top[u]], id[u]);
u = fa[top[u]];
}
if (dep[u] < dep[v]) swap(u, v);
res += query(id[v], id[u]);
return res;
}
// 快读 Fast read
template<typename tn> void read(tn &n)
{
tn s=0,flag=1;
char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') flag=-1;
for(;'0'<=ch&&ch<='9';ch=getchar()) s=s*10+ch-'0';
if(ch=='.')
{
ch=getchar();
tn r=0,R=1;
for(;'0'<=ch&&ch<='9';ch=getchar()) r=r*10+ch-'0',R*=10;
s+=r/R;
}
n=s*flag;
}
auto solve(){
int Q;
read(n),read(Q);
for(int i = 1;i <= n;i ++ ) h[i] = -1,w[i] = 1;
for(int i = 2;i <= n;i ++ ){
int f; read(f);
E[f].push_back(i);
add(i,f),add(f,i);
}
for(int i = 1;i <= n;i ++ ) read(d[i]);
init(n);
dfs1(1, -1, 1);
dfs2(1, 1);
while(Q -- ){
int op,x; read(op),read(x);
if(op == 1){ // 合并
vector<int> son;
//(1): 每次删掉节点 j ,即将节点 j 的值变成 0 ,(也就是-1)
for(int j : E[x]) son.push_back(j),d[x] += d[j],update_path(j,j,-1);;
E[x].clear();
for(int j : son)
for(int k : E[j])
E[x].push_back(k);
printf("%d %lld\n",(int)E[x].size(),d[x]);
}else{ // 询问路径
// (3): 询问1-x路径的权值之和(如果是0,就说明已经被删去)sum,sum即为答案
LL sum = query_path(1,x);
printf("%lld\n",sum);
}
}
}
signed main(){
int T = 1;
//cin >> T;
while(T -- ) solve();
//while(T -- ) cout << (solve() ? "YES" : "NO") << '\n';
return 0;
}
因为只需要单点改+区间查,所以把线段树爆改成树状数组就OK了