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;
}
时间: 2024-11-05 21:49:46

hdu 3974, 线段树的相关文章

hdu 3974 线段树 将树弄到区间上

Assign the task Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1647    Accepted Submission(s): 753 Problem Description There is a company that has N employees(numbered from 1 to N),every emplo

HDU 3974 线段树(将树映射到区间)

第一次写将树映射到区间的线段树... 线段树部分很简单 主要是将原有的关系树根据BOSS关系从新编号 以便把每个BOSS所带领的员工全部压入一个连续区间内 然后记录每个BOSS的起始编号和他的最后一名的员工的编号 然后用线段树成端更新,单点查找即可 #include "stdio.h" #include "string.h" struct node { int l,r,val,lazy; }data[200010]; struct Edge { int to,nex

HDU 4893 线段树裸题

Wow! Such Sequence! Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 2512    Accepted Submission(s): 751 Problem Description Recently, Doge got a funny birthday present from his new friend, Pro

HDU 4902 线段树(区间更新)

Nice boat Time Limit: 30000/15000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 353    Accepted Submission(s): 169 Problem Description There is an old country and the king fell in love with a devil. The devil alw

hdu 4893 线段树 --- 也是两个变 类似双标记

http://acm.hdu.edu.cn/showproblem.php?pid=4893 开始的时候,我按双标记,WA了一下午,搞不定,我是用的两个标记add--表示当前结点中有值发生变化,flag,斐波那契的懒惰标记,但是估计是我自己处理的有问题,一直不对 参考了别人的代码,写法还是很不错的,Add变量维护的是,完全变成Fibonacci的时候的和,---回头我再重新写一遍 #include <cstdio> #include <cstring> #include <a

HDU 4902 线段树||暴力

给定一个序列,两种操作 1:把一段变成x. 2:把一段每个数字,如果他大于x,就变成他和x的gcd,求变换完后,最后的序列. 线段树解法:用lazy标记下即可,优化方法还是很巧妙的, Accepted 4902 515MS 3308K 1941 B C++ #include "stdio.h" #include "string.h" struct node { int l,r,x;// 在叶子节点代表值,树节点代表成端更新的lazy操作. }data[400010]

HDU 4302 线段树单点更新,维护区间最大最小值

http://acm.hdu.edu.cn/showproblem.php?pid=4302 Problem Description Holedox is a small animal which can be considered as one point. It lives in a straight pipe whose length is L. Holedox can only move along the pipe. Cakes may appear anywhere in the p

HDU 3397 线段树 双懒惰标记

这个是去年遗留历史问题,之前思路混乱,搞了好多发都是WA,就没做了 自从上次做了大白书上那个双重懒惰标记的题目,做这个就思路很清晰了 跟上次大白上那个差不多,这个也是有一个sets标记,代表这个区间全部置为0或者1,没有置位的时候为-1 还有个rev标记,代表翻转操作,0代表当前不翻,1代表当前翻 要注意一下优先级,发现有不同的弄法,我是这个弄得,有set操作的时候,set标记设值,并把当前节点的rev标记设为0,因为不管要不要rev,当前set操作肯定直接覆盖了 rev操作不改变set操作,在

hdu 2795 线段树--点更新

http://acm.hdu.edu.cn/showproblem.php?pid=2795 多校的第一场和第三场都出现了线段树,比赛期间没做,,这两天先做几道热身下,然后31号之前把那两道多校的线段树都搞了,这是一道热身题 关键是建模: 首先一定看清楚题目构造的场景,看有什么特点--------会发现,如果尽量往左上放置的话,那么由于 the i-th announcement is a rectangle of size 1 * wi.,完全可以对h建立线段树,表示一行,结点里的l,r就表示