题意:
- 一个公司里面每个员工都有一个顶头上司,一旦给某个员工分配任务后,这个员工以及该员工的所有下属都在做该任务。
- 有若干操作,分配给员工任务以及查询该员工正在执行的任务。
题解:
典型的更新字树的操作,用时间戳来区分子树,然后用线段树做区间的修改和查询。简单介绍一下时间戳(按照dfs的顺寻把一个点第一次遍历的时间点 以及最后一次也就是第二次遍历到的时间点保存下来 具体看下图 会发现一个点的第一次和第二次的时间包含了同样标记的子节点第一次遍历的时间)
序列话之后,用线段树维护查询就好咯,注意一下建树的时候,大小别搞错了,,
上代码:
#include <cstdio> #include <iostream> #include <queue> #include <map> #include <cstring> #include <vector> #define maxn 50010 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; vector<int > edge[maxn]; int n,ret; int in[maxn*2],out[maxn*2]; // 这里的范围要注意一下 int lazy[maxn*4],val[maxn*4]; int vis[maxn]; void init() { ret=0; for(int i=0;i<=n;i++) { edge[i].clear(); vis[i]=0; } } void dfs(int x,int fa) { in[x]=++ret; int len=edge[x].size(); for(int i=0;i<len;i++) { if(edge[x][i]!=fa) { dfs(edge[x][i],x); } } out[x]=ret; } void build(int l,int r,int rt) { lazy[rt]=-1; val[rt]=-1; if(l==r) return; int m=(l+r)/2; build(lson); build(rson); } void pushdown(int rt) { if(lazy[rt]!=-1) { val[rt<<1]=lazy[rt]; val[rt<<1|1]=lazy[rt]; lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt]; lazy[rt]=-1; } } void update(int L,int R,int key,int l,int r,int rt) { if(L<=l && r<=R) { lazy[rt]=val[rt]=key; return; } pushdown(rt); int m=(l+r)/2; if(L<=m) update(L,R,key,lson); if(R>m) update(L,R,key,rson); } void query(int L,int R,int l,int r,int rt) { if(L<=l && r<=R) { cout<<val[rt]<<endl; return; } pushdown(rt); int m=(l+r)/2; if(L<=m) query(L,R,lson); if(R>m) query(L,R,rson); } int main() { int t,Case=0; cin>>t; while(t--) { cin>>n; init(); for(int i=1;i<n;i++) { int x,y; scanf("%d %d",&x,&y); vis[x]=1; // edge[x].push_back(y); edge[y].push_back(x); } for(int i=1;i<=n;i++) { if(vis[i]==0) { dfs(i,i); break; } } build(1,ret,1);// 对dfs序建树 printf("Case #%d: ",++Case); int q; cin>>q; while(q--) { char op[100]; cin>>op; if(op[0]=='C') { int x; scanf("%d",&x); query(in[x],in[x],1,ret,1); } else { int x,y; scanf("%d %d",&x,&y); update(in[x],out[x],y,1,ret,1); } } } return 0; }