hdu 3974, 线段树

题意:

有一个公司,有n个人;
这些人之间的关系是一棵树;
即:有的人是老板,有的人是员工,有的人既是老板,又是员工;
然后公司随时都会安排一些工作给他们做;
每次安排至安排一个人,但是他的下属会和他一起做;
题目就是查询当前这个人在做什么工作;

理解:
这个题的题意好理解,读几遍就知道了
但是对于已知的关系;
即:画出的公司员工之间的那棵树;
我是在无法联想到线段树;
之前还想怎么减小时间复杂度,然后暴力解决;
结果肯定是不行的;
所以只有向线段树想;
于是发现;
在分配了任务之后;
只有当前这个人和他的员工在做这个工作;
那么如果把这群人平铺下来;
即:把做一个工作的人放在一起,老板放在最前面;
然后发现;
通过这样做之后;
对于更新当前员工;
即是对他和他的下属的更新;
于是就是对上述平铺的数组中的某个区间进行更新;
这样就可以用到线段树了;

代码如下:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <ctime>

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <stack>

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

const double MIN_INF = 1e-7;
const int MAX_INF = (1e9) + 7;

#define X first
#define Y second

int tree[50005 * 4], add[50005 * 4];

void build(int rx, int l, int r) {
    if (l == r) {
        tree[rx] = -1;
        return ;
    }
    build(rx * 2, l, (l + r) / 2);
    build(rx * 2 + 1, (l + r) / 2 + 1, r);
    tree[rx] = -1;
}

void push_down(int rx) {
    tree[rx * 2] = tree[rx * 2 + 1] = add[rx];
    add[rx * 2] = add[rx * 2 + 1] = add[rx];
    add[rx] = -1;
}

void update(int rx, int L, int R, int l, int r, int y) {
    if (add[rx] != -1) {
        push_down(rx);
    }
    if (L >= l && r >= R) {
        add[rx] = y;
        tree[rx] = y;
        return ;
    }
    if (L > r || l > R) {
        return ;
    }
    update(rx * 2, L, (L + R) / 2, l, r, y);
    update(rx * 2 + 1, (L + R) / 2 + 1, R, l, r, y);
}

int query(int rx, int L, int R, int l, int r) {
    if (add[rx] != -1) {
        push_down(rx);
    }
    if (L >= l && r >= R) {
        return tree[rx];
    }
    if (L > r || l > R) {
        return -2;
    }
    int ans1 = query(rx * 2, L, (L + R) / 2, l, r);
    int ans2 = query(rx * 2 + 1, (L + R) / 2 + 1, R, l, r);
    if (ans1 != -2) {
        return ans1;
    }
    else {
        return ans2;
    }
}

void solve(vector<vector<int> > &vec, vector<int> &idl, vector<int> &len, int root, int &pos) {
    idl[root] = pos;
    for (int i = 0; i < vec[root].size(); ++i) {
        solve(vec, idl, len, vec[root][i], ++pos);
        len[root] += len[vec[root][i]];
    }
    len[root] += vec[root].size();
}

int main() {
    int t;
    cin >> t;
    for (int I = 1; I <= t; ++I) {
        memset(tree, -1, sizeof tree);
        memset(add, -1, sizeof add);
        int n;
        scanf("%d", &n);
        vector<vector<int> > vec(n + 2);
        vector<int> idl(n + 2, 0), len(n + 2, 0);
        for (int i = 0; i < n - 1; ++i) {
            int u, v;
            scanf("%d%d", &u, &v);
            vec[v].push_back(u);
            idl[u] = 1;
        }
        int root, pos = 1;
        for (int i = 1; i <= n; ++i) {
            if (idl[i] != 1) {
                root = i;
            }
        }
        solve(vec, idl, len, root, pos);

        printf("Case #%d:\n", I);
        build(1, 1, n);
        int m;
        scanf("%d", &m);
        while (m--) {
            string str;
            cin >> str;
            if (str[0] == 'T') {
                int x, y;
                scanf("%d%d", &x, &y);
                update(1, 1, n, idl[x], idl[x] + len[x], y);
            }
            else {
                int x;
                scanf("%d", &x);
                int ans = query(1, 1, n, idl[x], idl[x] + len[x]);
                printf("%d\n", ans);
            }
        }
    }

    return 0;
}

你可能感兴趣的:(线段树,HDU)