There is a company that has N employees(numbered from 1 to N),every employee in the company has a immediate boss (except for the leader of whole company).If you are the immediate boss of someone,that person is your subordinate, and all his subordinates are your subordinates as well. If you are nobody's boss, then you have no subordinates,the employee who has no immediate boss is the leader of whole company.So it means the N employees form a tree.
The company usually assigns some tasks to some employees to finish.When a task is assigned to someone,He/She will assigned it to all his/her subordinates.In other words,the person and all his/her subordinates received a task in the same time. Furthermore,whenever a employee received a task,he/she will stop the current task(if he/she has) and start the new one.
Write a program that will help in figuring out some employee’s current task after the company assign some tasks to some employee.
Input
The first line contains a single positive integer T( T <= 10 ), indicates the number of test cases.
For each test case:
The first line contains an integer N (N ≤ 50,000) , which is the number of the employees.
The following N - 1 lines each contain two integers u and v, which means the employee v is the immediate boss of employee u(1<=u,v<=N).
The next line contains an integer M (M ≤ 50,000).
The following M lines each contain a message which is either
"C x" which means an inquiry for the current task of employee x
or
"T x y"which means the company assign task y to employee x.
(1<=x<=N,0<=y<=10^9)
Output
For each test case, print the test case number (beginning with 1) in the first line and then for every inquiry, output the correspond answer per line.
Sample Input
1
5
4 3
3 2
1 3
5 2
5
C 3
T 2 1
C 3
T 3 2
C 3
Sample Output
Case #1:
-1
1
2
题意
n行u,v,v是u的顶层上司,m行命令,T是分配任务,C是查看任务,如果给x分配任务,那么他的直接下属和间接下属都会分配到该任务
思路
线段树专题,开始实在没想到这怎么搞成线段树,下属分散不知道怎么整成一个区间
看别人的blog是线段树+dfs序,我先去了解了这个dfs序
https://blog.csdn.net/qq_24489717/article/details/50569644
其余的看代码注释
我打代码比较繁杂,可以看别人的https://blog.csdn.net/qq_41428565/article/details/82460207虽然我也没看
代码
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#define rep(i,s,e) for(int i=s;i<=e;i++)
#define rep1(i,s,e) for(int i=s;i<e;i++)
#define rep2(i,s,e,c) for(int i=s;i>=e;i--)
#define pfi(x) printf("%d\n",x)
#define pfl(x) printf("%lld\n",x)
#define pfn() printf("\n")
#define pfs() printf(" ")
#define sfi(x) scanf("%d",&x)
#define sfi1(x,y) scanf("%d%d",&x,&y)
#define sff(x) scanf("%lf",&x)
#define sfl(x) scanf("%lld",&x)
#define memset1(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
const int MAX = 5e4 + 500;
const int mod = 996873654;
vector<int> vp[MAX];
int used[MAX],st[MAX],ed[MAX];
int index=0;
struct node{
int task;//正在执行什么工作
int p;//该区间属于哪个职员
int l,r;
int flag,flag1;//task和p的懒惰标记
}t[MAX<<2];
void dfs(int k){
st[k]=++index;
for(int i=0;i<vp[k].size();i++){//根据题意是有向无环简单树
dfs(vp[k][i]);
}
ed[k]=index;
}
void build(int left,int right,int k=1){
t[k].l=left; t[k].r=right; t[k].flag1=t[k].p=0; t[k].task=t[k].flag=-1;
if(left==right) return;
int mid=(left+right)>>1;
build(left,mid,k<<1);
build(mid+1,right,k<<1|1);
}
void down1(int k){
t[k<<1].flag1=t[k<<1|1].flag1=t[k<<1].p=t[k<<1|1].p=t[k].flag1;
t[k].flag1=0;
}
void next_build(int left,int right,int p,int k=1){
if(t[k].l>right || t[k].r<left) return;
if(left<=t[k].l&&t[k].r<=right){
t[k].p=p;
t[k].flag1=p;
return;
}
if(t[k].flag1) down1(k);
int mid=(t[k].l+t[k].r)>>1;
if(left<=mid) next_build(left,right,p,k<<1);
if(right>mid) next_build(left,right,p,k<<1|1);
}
void down(int k){
t[k<<1].flag=t[k<<1|1].flag=t[k<<1].task=t[k<<1|1].task=t[k].flag;
t[k].flag=-1;
}
void updates(int left,int right,int v,int k=1){
if(t[k].l>right || t[k].r<left) return;
if(left<=t[k].l&&t[k].r<=right){
t[k].task=v;//找到子区间,直接覆盖
t[k].flag=v;
return;
}
if(t[k].flag1) down1(k);
if(t[k].flag!=-1) down(k);
int mid=(t[k].l+t[k].r)>>1;
if(left<=mid) updates(left,right,v,k<<1);
if(right>mid) updates(left,right,v,k<<1|1);
}
int query(int left,int right,int p,int k=1){
if(t[k].l>right || t[k].r<left) return -1;
if(left<=t[k].l&&t[k].r<=right&&t[k].p==p){
return t[k].task;//如果找到一个区间和职员编号匹配,返回
}
if(t[k].l==t[k].r) return -1;//如果找到叶结点还不行,返回-1
if(t[k].flag1) down1(k);
if(t[k].flag!=-1) down(k);
int mid=(t[k].l+t[k].r)>>1;
int ans1=-1,ans2=-1;//初始化-1,否则如果左区间或右区间不需要查找,会干扰max
if(left<=mid) ans1=query(left,right,p,k<<1);
if(right>mid) ans2=query(left,right,p,k<<1|1);
return max(ans1,ans2);
}
int main(){
int T,k=0;
sfi(T);
while(T--){
printf("Case #%d:\n",++k);
memset1(used);
index=0;
int n;
sfi(n);
for(int i=0;i<=n;i++) vp[i].clear();
for(int i=0;i<n-1;i++){
int u,v;
sfi1(u,v);
vp[v].push_back(u);
used[u]=1;
}
//虚设一个0为总BOSS
for(int i=1;i<=n;i++){
if(!used[i]){//如果不是别人的下属,设置它的上司为0
vp[0].push_back(i);
}
}
dfs(0);
build(1,index);//初步初始化
queue<int> q;//此处从顶层上司开始给每一个区间添加属于哪一个职员
q.push(0);
while(q.size()){//按顺序添加保证不会弄混
int x=q.front();
q.pop();
next_build(st[x],ed[x],x);//进一步初始化区间属于哪个职员
for(int i=0;i<vp[x].size();i++){
q.push(vp[x][i]);
}
}
int m;
sfi(m);
char chars[3]; int x;
for(int i=0;i<m;i++){
scanf("%s%d",chars,&x);
if(chars[0]=='C'){
pfi(query(st[x],ed[x],x));
}
else{
int y;
sfi(y);
updates(st[x],ed[x],y);
}
}
}
return 0;
}