hdu 3974 Assign the task
2017-01-10 21:10
363 查看
Problem
acm.hdu.edu.cn/showproblem.php?pid=3974
题意
n 个员工之间的上司下属关系成一棵树,每个员工有一个上司(老板除外)和零个或多个下属。
有两种操作:
C x:询问编号为 x 的员工当前的工作
T x y:给编号为 x 的员工分配新工作 y
当员工被分配新工作时,旧工作被覆盖;该员工和他所有的下属(包扩下属的下属)同时被分配这个新工作(一次改整棵子树)。
分析
不太像以前的线段树,因为是多杈。但还是用到 lazy 标记。
用一个不压缩路径的并查集记录父结点信息,邻接表
4000
记录子结点信息。
更新时,就只修改那一个点的工作,还要记录这个工作分配的时间。信息本身也是个延迟标记。
查询时,从查询结点往根回溯,记录整条路径,然后自顶向下地 push_down ,然后返回查询结点更新后的工作。
Source code
#include <cstdio>
#include <stack>
#include <utility>
#include <vector>
using namespace std;
const int N = 50000;
vector<int> son[N+1]; // 每个结点的子结点
int fa[N+1]; // 每个结点的父结点
pair<int,int> task[N+1]; // first 表示时间,second 表示工作
void pushdown(int x)
{
int tm = task[x].first,
wk = task[x].second;
if(wk < 0) return;
for(vector<int>::iterator it=son[x].begin(); it!=son[x].end(); ++it)
if(task[*it].first < tm)
{
task[*it].first = tm;
task[*it].second = wk;
}
}
void update(int id, int w, int t)
{
task[id].first = t;
task[id].second = w;
}
int query(int x)
{
stack<int> path;
// 查询到根的路径
for(int y=x; ; y=fa[y])
{
path.push(y);
if(fa[y] == y)
break;
}
// 自顶向下更新
for( ; !path.empty(); path.pop())
pushdown(path.top());
return task[x].second;
}
int main()
{
int t, kase;
scanf("%d", &t);
for(kase=1; kase<=t; ++kase)
{
int n;
scanf("%d", &n);
for(int i=0; i<=n; ++i)
{
fa[i] = i;
son[i].clear();
task[i].first = task[i].second = -1;
}
for(int i=1,u,v; i<n; ++i)
{
scanf("%d%d", &u, &v);
fa[u] = v;
son[v].push_back(u);
}
int m;
scanf("%d", &m);
printf("Case #%d:\n", kase);
for(int time=0; time<m; ++time)
{
char op;
int x, y;
scanf(" %c", &op);
if(op == 'C')
{
scanf("%d", &x);
printf("%d\n", query(x));
}
else
{
scanf("%d%d", &x, &y);
update(x, y, time);
}
}
}
return 0;
}
acm.hdu.edu.cn/showproblem.php?pid=3974
题意
n 个员工之间的上司下属关系成一棵树,每个员工有一个上司(老板除外)和零个或多个下属。
有两种操作:
C x:询问编号为 x 的员工当前的工作
T x y:给编号为 x 的员工分配新工作 y
当员工被分配新工作时,旧工作被覆盖;该员工和他所有的下属(包扩下属的下属)同时被分配这个新工作(一次改整棵子树)。
分析
不太像以前的线段树,因为是多杈。但还是用到 lazy 标记。
用一个不压缩路径的并查集记录父结点信息,邻接表
4000
记录子结点信息。
更新时,就只修改那一个点的工作,还要记录这个工作分配的时间。信息本身也是个延迟标记。
查询时,从查询结点往根回溯,记录整条路径,然后自顶向下地 push_down ,然后返回查询结点更新后的工作。
Source code
#include <cstdio>
#include <stack>
#include <utility>
#include <vector>
using namespace std;
const int N = 50000;
vector<int> son[N+1]; // 每个结点的子结点
int fa[N+1]; // 每个结点的父结点
pair<int,int> task[N+1]; // first 表示时间,second 表示工作
void pushdown(int x)
{
int tm = task[x].first,
wk = task[x].second;
if(wk < 0) return;
for(vector<int>::iterator it=son[x].begin(); it!=son[x].end(); ++it)
if(task[*it].first < tm)
{
task[*it].first = tm;
task[*it].second = wk;
}
}
void update(int id, int w, int t)
{
task[id].first = t;
task[id].second = w;
}
int query(int x)
{
stack<int> path;
// 查询到根的路径
for(int y=x; ; y=fa[y])
{
path.push(y);
if(fa[y] == y)
break;
}
// 自顶向下更新
for( ; !path.empty(); path.pop())
pushdown(path.top());
return task[x].second;
}
int main()
{
int t, kase;
scanf("%d", &t);
for(kase=1; kase<=t; ++kase)
{
int n;
scanf("%d", &n);
for(int i=0; i<=n; ++i)
{
fa[i] = i;
son[i].clear();
task[i].first = task[i].second = -1;
}
for(int i=1,u,v; i<n; ++i)
{
scanf("%d%d", &u, &v);
fa[u] = v;
son[v].push_back(u);
}
int m;
scanf("%d", &m);
printf("Case #%d:\n", kase);
for(int time=0; time<m; ++time)
{
char op;
int x, y;
scanf(" %c", &op);
if(op == 'C')
{
scanf("%d", &x);
printf("%d\n", query(x));
}
else
{
scanf("%d%d", &x, &y);
update(x, y, time);
}
}
}
return 0;
}
相关文章推荐
- HDU - 3974 Assign the task(线段树 区间修改)
- HDU 3974 Assign the task 线段树(树映射到区间)
- HDU 3974 Assign the task 并查集/图论/线段树
- HDU 3974 Assign the task 暴力/线段树
- J - Assign the task - hdu 3974(DFS建树+简单线段树)
- hdu 3974 Assign the task
- hdu 3974 Assign the task (线段树)
- HDU 3974 Assign the task (线段树)
- J - Assign the task HDU 3974(线段树+dfs序)
- HDU 3974 Assign the task
- HDU 3974 Assign the task(简单线段树)
- HDU 3974 Assign the task (DFS序 + 线段树)
- hdu 3974 Assign the task
- HDU 3974 Assign the task(树 并查集)
- HDU 3974 Assign the task(并查集)
- HDU 3974 Assign the task
- HDU 3974 Assign the task(dfs时间戳+线段树成段更新)
- hdu 3974 Assign the task(线段树+将树映射到区间)
- HDU 3974 Assign the task [并查集扩展]
- HDU 3974 Assign the task(线段树 单点更新+lazy)