1. 程式人生 > >HDU3974 Assign the task(多叉樹轉換為線段+線段樹區間染色)

HDU3974 Assign the task(多叉樹轉換為線段+線段樹區間染色)

結束 turn amp cas truct 沒有 遍歷 || 們的

題目大意:有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(多叉樹轉換為線段+線段樹區間染色)