题目链接
解题思路
一道DFS序的好题。
DFS序想必大家都知道,就是用DFS遍历树或图时访问节点的顺序。我们一般说的DFS序,都是指树的DFS序。以下的DFS序都是从根开始的树上DFS序。
DFS序有一个重要的性质:任何一个子树,它的节点在DFS序中一定排成连续的一段。这时,我们就可以把某些修改子树+查询问题转为区间修改+查询问题。
我们这一题实际上就是线段树。先搞DFS序,记录每一个节点对应的区间,然后线段树即可。
代码实现
#include <iostream>
#include <bitset>
#include <vector>
#include <array>
using namespace std;
int cur_points;
bitset<800001> lazy_tag;
array<int,200001> val_inital,values;
array<int,800001> segment_tree;
array<vector<int>,200001> tree;
array<pair<int,int>,200001> ranges;
inline int l_son(int num)
{
return num<<1;
}
inline int r_son(int num)
{
return num<<1|1;
}
inline void push_up(int pos)
{
segment_tree[pos]=segment_tree[l_son(pos)]+segment_tree[r_son(pos)];
}
void build(int left,int right,int pos)
{
if(left==right)
return (void)(segment_tree[pos]=values[left]);
int mid=(left+right)>>1;
build(left,mid,l_son(pos)),build(mid+1,right,r_son(pos));
push_up(pos);
}
inline void set_tag(int left,int right,bool val,int pos)
{
if(val)
lazy_tag.flip(pos),segment_tree[pos]=right-left+1-segment_tree[pos];
}
inline void push_down(int left,int right,int pos)
{
int mid=(left+right)>>1;
set_tag(left,mid,lazy_tag[pos],l_son(pos));
set_tag(mid+1,right,lazy_tag[pos],r_son(pos));
lazy_tag.reset(pos);
}
void update(const int& q_left,const int& q_right,int n_left,int n_right,bool val,int pos)
{
if(n_left>=q_left&&n_right<=q_right)
return set_tag(n_left,n_right,val,pos);
int mid=(n_left+n_right)>>1;
push_down(n_left,n_right,pos);
if(q_left<=mid)
update(q_left,q_right,n_left,mid,val,l_son(pos));
if(q_right>mid)
update(q_left,q_right,mid+1,n_right,val,r_son(pos));
push_up(pos);
}
long long range_sum(const int& q_left,const int& q_right,int n_left,int n_right,int pos)
{
long long result=0;
if(n_left>=q_left&&n_right<=q_right)
return segment_tree[pos];
int mid=(n_left+n_right)>>1;
push_down(n_left,n_right,pos);
if(q_left<=mid)
result+=range_sum(q_left,q_right,n_left,mid,l_son(pos));
if(q_right>mid)
result+=range_sum(q_left,q_right,mid+1,n_right,r_son(pos));
return result;
}
int DFS(int root)
{
ranges[root].first=++cur_points;
values[cur_points]=val_inital[root];
for(const int& tmp:tree[root])
DFS(tmp);
ranges[root].second=cur_points;
}
int main(int argc,char* argv[],char* envp[])
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int cnt,cntquery,tmp;
cin>>cnt;
for(int i=2;i<=cnt;i++)
cin>>tmp,tree[tmp].push_back(i);
for(int i=1;i<=cnt;i++)
cin>>val_inital[i];
DFS(1);
build(1,cnt,1);
cin>>cntquery;
while(cntquery--)
{
char type;
int param;
(cin>>type).ignore(3,' ')>>param;
if(type=='p')
update(ranges[param].first,ranges[param].second,1,cnt,true,1);
else
cout<<range_sum(ranges[param].first,ranges[param].second,1,cnt,1)<<'\n';
}
return 0;
}