题目大意:有n个人,给你他们的关系(老板和员工),没有直属上司的人就是整个公司的领导者,这意味着n个人形成一棵树(多叉树)。当一个人被分配工作时他会让他的下属也做同样的工作(并且立即停止手头正在做的工作),题目会询问你其中某个人正在做的工作。
解题思路:其实从“一个人分配他的下属做一样的工作”这里就可以看出来了,这相当于让一块区间的人都做一样的事,就是线段树区间染色问题。但不能使用线段树,要先将多叉树铺展开,将节点映射到线段上。把每个人的管理区段找出来(把属于同一个人管的放一起,上司放在前面),这样对某个员工更新也就是对他和他下属的更新。具体实现就是先将多叉树保存下来,用dfs遍历多叉树给每个人打上时间戳,分配序号就行了。
1 #include<iostream> 2 #include<cstring> 3 #include<vector> 4 #define LC(a) ((a<<1)) 5 #define RC(a) ((a<<1)+1) 6 #define MID(a,b) ((a+b)>>1) 7 using namespace std; 8 const int N=5e4+5; 9 typedef long long ll; 10 11 vector<ll>v[N]; 12 ll Start[N],End[N];//每个员工所有下属的开始和结束节点,包含本身 13 ll ans,cnt;//cnt用于记录节点的编号 14 bool used[N]; 15 16 void dfs(ll rt){ 17 Start[rt]=++cnt; 18 for(int i=0;i<v[rt].size();i++){ 19 dfs(v[rt][i]); 20 } 21 End[rt]=cnt; 22 } 23 24 struct node{ 25 ll l,r; 26 ll task;//task=-2表示下属工作不同 27 }tree[N*4]; 28 29 void pushup(ll p){ 30 tree[p].task=(tree[LC(p)].task==tree[RC(p)].task?tree[LC(p)].task:-2); 31 } 32 33 void pushdown(ll p){ 34 tree[LC(p)].task=tree[RC(p)].task=tree[p].task; 35 } 36 37 void build(ll p,ll l,ll r){ 38 tree[p].l=l; 39 tree[p].r=r; 40 tree[p].task=-1; 41 if(l==r){ 42 return; 43 } 44 build(LC(p),l,MID(l,r)); 45 build(RC(p),MID(l,r)+1,r); 46 } 47 48 void update(ll p,ll l,ll r,ll task){ 49 if(r<tree[p].l||l>tree[p].r) 50 return; 51 if(l<=tree[p].l&&r>=tree[p].r){ 52 tree[p].task=task; 53 return; 54 } 55 if(tree[p].task!=-2) 56 pushdown(p); 57 update(LC(p),l,r,task); 58 update(RC(p),l,r,task); 59 pushup(p); 60 } 61 62 void query(ll p,ll t){ 63 if(tree[p].task!=-2){ 64 ans=tree[p].task; 65 return; 66 } 67 ll mid=MID(tree[p].l,tree[p].r); 68 if(t<=mid) 69 query(LC(p),t); 70 else 71 query(RC(p),t); 72 } 73 74 int main(){ 75 ios::sync_with_stdio(false); 76 ll t; 77 ll cas=0; 78 cin>>t; 79 while(t--){ 80 cas++; 81 //初始化 82 cnt=0; 83 memset(used,false,sizeof(used)); 84 for(int i=1;i<=N;i++){ 85 v[i].clear(); 86 } 87 88 ll n; 89 cin>>n; 90 for(int i=1;i<=n-1;i++){ 91 ll rt,chd; 92 cin>>chd>>rt; 93 used[chd]=true; 94 v[rt].push_back(chd); 95 } 96 //将多叉树转化为线段 97 for(int i=1;i<=n;i++){ 98 //找到根结点 99 if(!used[i]){ 100 dfs(i); 101 break; 102 } 103 } 104 //建树 105 build(1,1,n); 106 ll m; 107 cout<<"Case #"<<cas<<":"<<endl; 108 cin>>m; 109 for(int i=1;i<=m;i++){ 110 char op; 111 cin>>op; 112 if(op==‘C‘){ 113 ll x,t; 114 cin>>x; 115 t=Start[x]; 116 query(1,t); 117 cout<<ans<<endl; 118 } 119 else{ 120 ll x,l,r,task; 121 cin>>x>>task; 122 l=Start[x]; 123 r=End[x]; 124 update(1,l,r,task); 125 } 126 } 127 } 128 }
HDU3974 Assign the task(多叉树转换为线段+线段树区间染色)
原文:http://www.cnblogs.com/fu3638/p/7148304.html