hdu 3974 Assign the task

本文介绍了一道题目HDU 3974的解决方案,该题涉及员工间的上下级关系构成的树形结构。通过使用不压缩路径的并查集来记录父节点信息,并结合邻接表记录子节点信息,实现了一种利用懒惰标记的高效算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem

acm.hdu.edu.cn/showproblem.php?pid=3974

题意

n 个员工之间的上司下属关系成一棵树,每个员工有一个上司(老板除外)和零个或多个下属。

有两种操作:

C x:询问编号为 x 的员工当前的工作

T x y:给编号为 x 的员工分配新工作 y

当员工被分配新工作时,旧工作被覆盖;该员工和他所有的下属(包扩下属的下属)同时被分配这个新工作(一次改整棵子树)。

分析

不太像以前的线段树,因为是多杈。但还是用到 lazy 标记。

用一个不压缩路径的并查集记录父结点信息,邻接表记录子结点信息。

更新时,就只修改那一个点的工作,还要记录这个工作分配的时间。信息本身也是个延迟标记。

查询时,从查询结点往根回溯,记录整条路径,然后自顶向下地 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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值