写了几道线段树的题目,感觉基础线段树的题目除了在更新和查询上做一些文章以外,还有就是这种在建树上设置一些门槛的题目了,感觉这道题目除了找dfs序列的过程就剩下裸的线段树了。这个用dfs序建树的过程,往往就是题目当中抽象成模型的重要过程。
题意:一棵树的结构,父节点是老板,子节点是员工,每次给父节点分配的任务,立即会下分到他所有的子节点,有更新和查询命令。
解题过程:建立DFS序感觉对于这种需要用节点间前驱于后继关系将节点串联成图的题目应该是关键的切入点,感觉这种思想是以后解题中很可能多次运用到的。
DFS序:由于题目给定的节点之间的关系可得一个树以及树的根节点,由根节点遍历完整颗树得到的序列就是dfs序。
为什么要用dfs序建树?
因为根据题目的需求,我需要就是可以将一个节点所包含的所有节点全部更新,这正好对应的就是线段树操作中的区间更新,
怎样才能在线段树中区间更新一个节点的所有子节点呢?这个节点和他们的子节点必须连续;
通过dfs序得到一个序列如果作为一颗线段树最下层的子节点的话正好满足这个要求,每个节点的所有子节点都跟在这个节点的后面,这种形式可以直接找到任何一个节点所包含所有子节点的区间,进行区间更新。
另外一点需要注意的就是,因为题目说每个人接到新工作就会停止手头的工作,这个线段树中不能通过任何一个根节点体现所包含节点的情况,所以必须查线段树的最下层,就是查到每一个要查的节点而不是查到包含他的区间。
#include<iostream>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
struct node{
int l,r;
int work,lazy;
}tree[4*50005];
vector<int>map[50005];
int len,vis[50005],ll[50005],rr[50005];
void dfs(int x){
++len;
vis[x]=1;
ll[x]=len;
for(int i=0;i<map[x].size();i++){
dfs(map[x][i]);
}
rr[x]=len;
}
void build(int i,int l,int r){
tree[i].l=l;tree[i].r=r;
tree[i].work=-1;tree[i].lazy=0;
if(l==r)
return;
build(i<<1,l,(int)floor((r+l)/2.0));
build((i<<1)+1,(int)floor((r+l)/2.0)+1,r);
}
void pushdown(int i){
tree[i<<1].lazy=tree[(i<<1)+1].lazy=1;
tree[i<<1].work=tree[(i<<1)+1].work=tree[i].work;
tree[i].lazy=0;
}
int ans=0;
void que(int i,int id){
if(tree[i].l==tree[i].r&&tree[i].l==id){
ans=tree[i].work;
return;
}
if(tree[i].lazy){
pushdown(i);
}
int mid=(tree[i].l+tree[i].r)>>1;
if(id<=mid){
que(i<<1,id);
}
else{
que((i<<1)+1,id);
}
}
void update(int i,int l,int r,int w){
if(tree[i].l>=l&&tree[i].r<=r){
tree[i].work=w;
tree[i].lazy=1;
return;
}
if(tree[i].r<l||tree[i].l>r){
return;
}
if(tree[i].lazy){
pushdown(i) ;
}
update(i<<1,l,r,w);
update((i<<1)+1,l,r,w);
}
int main(){
int t,flag=1;
cin>>t;
while(t--){
int n,m;
cin>>n;
len=0;
memset(vis,0,sizeof(vis));
// memset(ll,0,sizeof(ll));
// memset(rr,0,sizeof(rr));
for(int i=1;i<=n;i++)
map[i].clear();
for(int i=1;i<n;i++){
int u,v;
cin>>v>>u;
map[u].push_back(v);
vis[v]=1;
// cout<<"asdf"<<endl;
}
for(int i=1;i<=n;i++){
if(!vis[i]){
dfs(i);
break;
}
}
// cout<<len<<endl;
build(1,1,len);
char s[5];
cout<<"Case #"<<flag++<<":"<<endl;
cin>>m;
while(m--){
cin>>s;
if(s[0]=='C'){
int id;
cin>>id;
ans=-1;
que(1,ll[id]);
cout<<ans<<endl;
}
else{
int id,wo;
cin>>id>>wo;
update(1,ll[id],rr[id],wo);
}
}
}
return 0;
}