Assign the task HDU - 3974(DFS序+线段树)

DFS序

DFS序是根据DFS遍历树的结点的入栈出栈顺序来给节点赋值的,如下图,黑色的是节点本身的编号,红色的是DFS序以后的数组,数组两个相同的数字之前的标号的的节点,是这个节点的子树,比如红色的2节点,中间有1,3,4三个标号,代表1,3,4是2的子树,将树形结构变成线性结构后,我们就可以用树状数组或者线段树进行操作了
在这里插入图片描述

题面

有一家公司有 N 名员工(从 1 到 N 编号),公司的每个员工都有一个直属上司(全公司的领导除外)。如果你是某人的直属上司,那人就是你的下属,他所有的下属也是你的下属。如果你不是任何人的老板,那么你就没有下属,没有直接上司的员工就是整个公司的领导者。所以这意味着N个员工组成了一棵树。

公司通常将一些任务分配给一些员工完成。当一个任务分配给某人时,他/她会将其分配给他/她的所有下属。换句话说,这个人和他/她的所有下属都收到了一个任务。同时。此外,每当员工收到任务时,他/她将停止当前任务(如果他/她有)并开始新的任务。

在公司将一些任务分配给某个员工之后,编写一个程序来帮助确定某个员工的当前任务。

输入
第一行包含一个正整数 T( T <= 10 ),表示测试用例的数量。

对于每个测试用例:

第一行包含一个整数 N (N ≤ 50,000) ,即员工人数。

下面的 N - 1 行每行包含两个整数 u 和 v,这意味着员工 v 是员工 u 的直接老板 (1<=u,v<=N)。

下一行包含一个整数 M (M ≤ 50,000)。

以下 M 行每行包含一条消息,

“C x”表示查询员工 x 的当前任务,

“T x y”表示公司将任务 y 分配给员工 x。

(1<=x<=N,0<=y<=10^9)

样例
1
5
4 3
3 2
1 3
5 2
5
C 3
T 2 1
C 3
T 3 2
C 3

输出
Case #1:
-1
1
2

题解

题目上暗示的很明显是一个线段树操作的题,但是建树只能在一维数组的基础上去赋值建树,这道题的关系很显然是树形结构的,不可以直接去建树,就需要引用到知识点DFS序,把一整棵树变成一个一个一维的数组,然后就是正常的区间修改单点查询了。

AC代码

#include <algorithm>
#include <bitset>
#include <cctype>
#include <cerrno>
#include <clocale>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <limits>
#include <list>
#include <map>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <utility>
#include <vector>
#include <cwchar>
#include <cwctype>
#define int long long
#define gcd __gcd
#define endl '\n'
#define mem(x, y) memset(x, y, sizeof(x))
#define inf 0x3f3f3f
#define ninf 0xc0c0c0c0
#define FAST ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
using namespace std;
typedef pair<int, int> PII;
const int N = 50010;
bool vis[N];
int ll[N], rr[N];
int idx, n, m;
vector<int> mp[N];
struct tree
{
    int l, r, w, lazy;
    int mid() { return l + r >> 1; }
} t[N << 2];

void build(int f, int l, int r)
{
    t[f] = {l, r, -1, -1};
    if (l == r)
        return;
    int mid = t[f].mid();
    build(f << 1, l, mid);
    build(f << 1 | 1, mid + 1, r);
}

void pushdown(int f)
{
    t[f << 1 | 1].w = t[f << 1 | 1].lazy = t[f << 1].w = t[f << 1].lazy = t[f].lazy;
    t[f].lazy = -1;
}

void dfs(int u)
{
    ll[u] = ++m;
    for (int i = 0; i < mp[u].size(); i++)
    {
        int v = mp[u][i];
        dfs(v);
    }
    rr[u] = m;
}

void change(int f, int l, int r, int x)
{
    if (t[f].l >= l && t[f].r <= r)
    {
        t[f].w = t[f].lazy = x;
        return;
    }
    if (t[f].lazy != -1)
        pushdown(f);
    int mid = t[f].mid();
    if (r <= mid)
        change(f << 1, l, r, x);
    else if (l > mid)
        change(f << 1 | 1, l, r, x);
    else
        change(f << 1, l, mid, x), change(f << 1 | 1, mid + 1, r, x);
}

int query(int f, int x)
{
    if (t[f].l == x && t[f].r == x)
        return t[f].w;
    if (t[f].lazy != -1)
        pushdown(f);
    int mid = t[f].mid();
    if (x <= mid)
        return query(f << 1, x);
    else
        return query(f << 1 | 1, x);
}
int cnt;
void solve()
{

    cin >> n;
    for (int i = 1; i <= n; i++)
        mp[i].clear();
    memset(vis, 0, sizeof(vis));
    for (int i = 1; i <= n - 1; i++)
    {
        int u, v;
        cin >> u >> v;
        mp[v].push_back(u);
        vis[u] = 1;
    }

    for (int i = 1; i <= n; i++)
    {
        if (!vis[i])
        {
            m = 0;
            memset(vis, 0, sizeof(ll));
            memset(vis, 0, sizeof(rr));
            dfs(i);
            break;
        }
    }

    build(1, 1, n);

    cin >> m;
    cout << "Case #" << cnt++ << ":\n";
    // cout << m << " \n";
    for (int i = 1; i <= m; i++)
    {

        string a;
        cin >> a;

        if (a[0] == 'C')
        {
            int x;
            cin >> x;

            cout << query(1, ll[x]) << endl;
        }
        else if (a[0] == 'T')
        {
            int x, y;
            cin >> x >> y;
            change(1, ll[x], rr[x], y);
        }
    }
}
signed main()
{
    FAST;
    cnt = 1;
    int t;
    cin >> t;
    while (t--)
        solve();
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值