HDU3974 Assign the task(多叉树转换为线段+线段树区间染色)

题目大意:有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 }

 

posted @ 2017-07-10 23:45  Yeader  阅读(452)  评论(0编辑  收藏  举报