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 }
时间: 2024-11-01 13:37:34

HDU3974 Assign the task(多叉树转换为线段+线段树区间染色)的相关文章

POJ 2528 Mayor&#39;s posters(线段树区间染色+离散化或倒序更新)

Mayor's posters Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 59239   Accepted: 17157 Description The citizens of Bytetown, AB, could not stand that the candidates in the mayoral election campaign have been placing their electoral post

HDU 3974 Assign the task 并查集/图论/线段树

Assign the task Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=3974 Description 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 l

ZOJ 1610 线段树区间染色

给长度8000米的板,对其中区间染色,问最后能看到的颜色,和该颜色一共出现了几段 线段覆盖法 数据比较水   也可以暴力水过 线段树: #include "stdio.h" #include "string.h" struct node { int l,r,c; }data[40010]; int color[8011]; void build(int l,int r,int k) { int mid; data[k].l=l; data[k].r=r; data[

POJ2777 线段树区间染色问题

题意:给L长度的木板,给T种颜色,给O个操作,每次可以选择一段区间染色,或查询一个区间的颜色种类 思路:用线段树叶节点记录颜色所代表的数字,父节点为-1表示两个子节点颜色不相同,>0时的数字代表子节点全为这个数字对应颜色. #include <iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std

J - Assign the task - hdu 3974(多操作混合区间更新)线段树

题意:有四种操作 1,  区间 [l, r] 的值都加上 C 2,  区间 [l, r] 的值都乘上 C 3,  区间 [l, r] 的值都变为C 4,  求区间 [l, r]所有数的p次方的和 分析:是比较麻烦的区间操作,设计四种操作,更新的时候无法更新到底部,不过仔细思考可以想到这都是对区间进行的操作,所以会造成一部分的区间值相等,所以只需要更新到相等区间部分就行了,而且注意有第三种操作的时候,第二和第一种操作可以去掉,操作的优先性是3>2>1,. WA了一次,因为操作三进行的的时候没有把

TyvjOJ题目 P1473 校门外的树3(线段树区间染色种类数不覆盖)

P1473 校门外的树3 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的-- 如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作: K=1,读入l,r表示在l~r之间种上的一种树 K=2,读入l,r表示询问l~r之间能见到多少种树 (l,r>0) 输入格式 第一行n,m表示道路总长为n,共有m个操作 接下来m行为m个操作 输出格式 对于每个k=

HDU 5023线段树区间染色,统计区间内颜色个数

这个也是一个线段树的模板 #include<iostream> #include<string.h> #include<algorithm> #include<stdio.h> #include<set> using namespace std; const int maxx = 1000050; set<int>s; struct node{ int color; int left; int right; int mid; }a[m

Count Color (线段树区间染色?二进制状态压缩)

题目链接:https://vjudge.net/problem/POJ-2777 题意: 有L个画板,30种颜色,o个操作:P a b :询问a-b 种有多少种颜色不同的,C  a b c:把a-b全部涂成c的颜色(覆盖掉) 1 #include <stdio.h> 2 #include <algorithm> 3 #include <iostream> 4 #include <cstring> 5 #include <string> 6 #in

线段树+dfs序(Apple Tree )(Assign the task )

线段树+dfs序 给定一棵n个节点的树,m次查询,每次查询需要求出某个节点深度为h的所有子节点. 作为预处理,首先将树的所有节点按深度保存起来,每个深度的所有节点用一个线性结构保存,每个深度的节点相对顺序要和前序遍历一致. 然后从树的根节点进行dfs,对于每个节点记录两个信息,一个是dfs进入该节点的时间戳in[id],另一个是dfs离开该节点的时间戳out[id]. 最后对于每次查询,求节点v在深度h的所有子节点,只需将深度为h并且dfs进入时间戳在in[v]和out[v]之间的所有节点都求出