您的位置:首页 > 其它

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: