题目: link.
题意:
公司里有一堆人,然后对于每个人(除了公司老板)每个人都有上属和下属,他们恰好构成一棵树,每当把任务分给某个人时,若他有下属,则他的所有子树全部做这个任务,对于每次查询输出某个节点正在做什么任务。
输入有2种操作:
1、C x 输入x这个人在做的任务编号 如果没工作输出-1
2、T x y 让x和x的下属做编号为y的工作
思路:
先跑一边dfs序,每个节点记录一个in和out表示时间戳,对于每个人p,in[p]到out[p]这段区间就是p的下属,dfs序完了之后用线段树维护每个人的工作,比如一个人p的工作变为y,把y一直pushdown给p的下属,update的区间就是in[p]到out[p]。
第一次碰到dfs序的题,看了题解才理解这道题,很牛逼
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <map>
#include <queue>
#include <vector>
#define ll long long
#define T int T;scanf("%d", &T);while(T--)
#define inf 0x7f7f7f7f
using namespace std;
const int maxn = 5e4+10;
struct node{
ll sum;
int l,r;
ll lazy;
}tree[maxn<<2];
vector<int> g[maxn];
bool vis[maxn];
int in[maxn];
int out[maxn];
int n,m;
int cnt;
void init(){
memset(vis,false,sizeof(vis));
for(int i = 0; i < n+5; i ++){
g[i].clear();
}
cnt = 0;
}
void build(int l, int r, int index){
tree[index].l = l;
tree[index].r = r;
tree[index].lazy = -1; //初值都为-1
if(l==r){
tree[index].sum = -1; //初值都为-1,表示没工作
return;
}
int mid = (l+r)/2;
build(l,mid,index*2);
build(mid+1,r,index*2+1);
}
void pushdown(int index){
if(tree[index].lazy==-1) return; //如果没新的工作不用向下更新
tree[index*2].lazy = tree[index].lazy;
tree[index*2+1].lazy = tree[index].lazy;
tree[index*2].sum = tree[index].lazy;
tree[index*2+1].sum = tree[index].lazy;
tree[index].lazy = -1;
}
void update(int l, int r,int w,int index){ //正常区间更新
if(l<=tree[index].l && tree[index].r<=r){
tree[index].lazy = w;
tree[index].sum = w;
return;
}
pushdown(index);
int mid = (tree[index].l+tree[index].r)/2;
if(l<=mid) update(l,r,w,index*2);
if(r>mid) update(l,r,w,index*2+1);
}
void query(int p,int index){ //正常单点查询
if(tree[index].l==tree[index].r){
printf("%lld\n", tree[index].sum);
return;
}
pushdown(index);
int mid = (tree[index].l+tree[index].r)/2;
if(p<=mid) query(p,index*2);
else query(p,index*2+1);
}
void dfs(int u){ //dfs序,记录时间戳
in[u] = ++cnt; //in[] 记录u点第一个下属,即自己
for(auto i : g[u]){
dfs(i);
}
out[u] = cnt; //out记录u的最后一个下属
}
int main(){
int tt = 1;
T{
scanf("%d", &n);
init();
build(1,n,1);
for(int i = 1; i < n; i ++){
int u,v;
scanf("%d %d", &u, &v);
g[v].push_back(u); //u是v的下属
vis[u] = true; //有领导
}
for(int i = 1; i <= n; i ++){
if(vis[i]==false){ //没领导,即根结点
dfs(i);
break;
}
}
printf("Case #%d:\n", tt++);
scanf("%d", &m);
char c;
int x,y;
while(m--){
cin >> c;
if(c=='C'){
scanf("%d", &x);
query(in[x],1); //查x这个人的工作
}else{
scanf("%d %d", &x, &y);
update(in[x],out[x],y,1); //更新x的所有下属,即in到out这个区间
}
}
}
return 0;
}