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 employee in the company has a immediate boss (except for the leader of whole company).If you are the immediate boss of someone,that person is your subordinate, and all his subordinates are your subordinates as well. If you are nobody‘s boss, then you have no subordinates,the employee who has no immediate boss is the leader of whole company.So it means the N employees form a tree.

The company usually assigns some tasks to some employees to finish.When a task is assigned to someone,He/She will assigned it to all his/her subordinates.In other words,the person and all his/her subordinates received a task in the same time. Furthermore,whenever a employee received a task,he/she will stop the current task(if he/she has) and start the new one.

Write a program that will help in figuring out some employee’s current task after the company assign some tasks to some employee.

Input

The first line contains a single positive integer T( T <= 10 ), indicates the number of test cases.

For each test case:

The first line contains an integer N (N ≤ 50,000) , which is the number of the employees.

The following N - 1 lines each contain two integers u and v, which means the employee v is the immediate boss of employee u(1<=u,v<=N).

The next line contains an integer M (M ≤ 50,000).

The following M lines each contain a message which is either

"C x" which means an inquiry for the current task of employee x

or

"T x y"which means the company assign task y to employee x.

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

Output

For each test case, print the test case number (beginning with 1) in the first line and then for every inquiry, output the correspond answer per line.

Sample Input

1
5
4 3
3 2
1 3
5 2
5
C 3
T 2 1
C 3
T 3 2
C 3

Sample Output

Case #1:
-1
1
2

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

题意: 给定一棵树,50000个节点,50000个操作
C x表示查询x节点的值,
T x y表示更新x节点及其子节点的值为y

没想到的是普通并查集都能过,数据是由多水 - -

由于T操作每次更新当前节点以及它的子树,所有dfs一次,给每个节点进行编号。 每次更新
就成了对当前节点所覆盖区间的更新。

hhh-2016-04-22 14:09:04
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <functional>
using namespace std;
#define lson  (i<<1)
#define rson  ((i<<1)|1)
typedef long long ll;
using namespace std;
const ll mod = 1e9 + 7;
const int  maxn = 50010;

struct node
{
    int l,r;
    int val;
    int lazy;
    int mid() {return (l+r) >> 1;}
}tree[maxn<<2];

int tot,cnt;
int rt[maxn];
int st[maxn],ed[maxn];
vector <int > vec[maxn];
void dfs(int cur)
{
    st[cur] = ++cnt;
    for(int i = 0;i < vec[cur].size();i++)
    {
        dfs(vec[cur][i]);
    }
    ed[cur] = cnt;
}

void build(int i,int l,int r)
{
    tree[i].l = l,tree[i].r = r;
    tree[i].val = -1,tree[i].lazy = 0;
    if(l == r)
        return ;
    int mid = tree[i].mid();
    build(lson,l,mid);
    build(rson,mid+1,r);
}

void push_down(int i)
{
    if(tree[i].lazy)
    {
        tree[lson].val = tree[i].val,tree[lson].lazy = 1;
        tree[rson].val = tree[i].val,tree[rson].lazy = 1;
        tree[i].lazy = 0;
    }
}

void update(int i,int l,int r,int val)
{
    if(tree[i].l >= l && tree[i].r <= r)
    {
         tree[i].val = val;
         tree[i].lazy = 1;
         return ;
    }
    push_down(i);
    int mid = tree[i].mid();
    if(l <= mid)
        update(lson,l,r,val);
    if(r > mid)
        update(rson,l,r,val);
//    if(r <= mid)
//        update(lson,l,r,val);
//    else if(l > mid)
//        update(rson,l,r,val);
//    else
//    {
//        update(lson,l,mid,val);
//        update(rson,mid+1,r,val);
//    }
    return ;
}

int query(int i,int k)
{
    if(tree[i].l == k && tree[i].r == k)
        return tree[i].val;
    int mid = tree[i].mid();
    push_down(i);
    if(k <= mid)
        return query(lson,k);
    else
        return query(rson,k);
}

int main()
{
    int T,n,m,x,y;
    int cas = 1;
    scanf("%d",&T);
    while(T--)
    {
        cnt = 0;
        scanf("%d",&n);
        printf("Case #%d:\n",cas++);
        for(int i = 1;i <= n;i++)
        {
            vec[i].clear();
        }
        memset(rt,0,sizeof(rt));
        int u,v;
        for(int i = 1;i < n;i++)
        {
            scanf("%d%d",&u,&v);
            vec[v].push_back(u);
            rt[u] = 1;
        }
        int rot;
        for(int i = 1;i <= n;i++)
        {
            if(!rt[i])
            {
                rot = i;
                break;
            }
        }
        dfs(rot);
        build(1,1,cnt);
        char op[10];
        scanf("%d",&m);
        for(int i = 1;i <= m;i++)
        {
            scanf("%s",op);
            if(op[0] == ‘C‘)
            {
                scanf("%d",&x);
                printf("%d\n",query(1,st[x]));
            }
            else if(op[0] == ‘T‘)
            {
                scanf("%d%d",&x,&y);
                update(1,st[x],ed[x],y);
            }
        }
    }
    return 0;
}

  

时间: 2024-10-09 02:09:35

hdu 3974 线段树 将树弄到区间上的相关文章

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 3974, 线段树

题意: 有一个公司,有n个人: 这些人之间的关系是一棵树: 即:有的人是老板,有的人是员工,有的人既是老板,又是员工: 然后公司随时都会安排一些工作给他们做: 每次安排至安排一个人,但是他的下属会和他一起做: 题目就是查询当前这个人在做什么工作: 理解: 这个题的题意好理解,读几遍就知道了 但是对于已知的关系: 即:画出的公司员工之间的那棵树: 我是在无法联想到线段树: 之前还想怎么减小时间复杂度,然后暴力解决: 结果肯定是不行的: 所以只有向线段树想: 于是发现: 在分配了任务之后: 只有当前

HDU 3974 Assign the task(树 并查集)

题意  公司中有n个员工  除了boss  每个员工都有自己的上司  自己下属的下属也是自己的下属  当给一个员工分配任务时  这个员工会把任务也分配到自己的所有下属   每个员工都只做最后一个被分配的任务  对于每个C x  输出员工x正在做的任务  没有就输出-1 把员工的关系数建成类似并查集的结构  把每个直接分配任务的员工的任务和任务分配时间保存起来  查询时只要找这个员工所有父节点中最晚分配的任务 #include <bits/stdc++.h> using namespace st

HDU - 3974 Assign the task (线段树区间修改+构建模型)

https://cn.vjudge.net/problem/HDU-3974 题意 有一棵树,给一个结点分配任务时,其子树的所有结点都能接受到此任务.有两个操作,C x表示查询x结点此时任务编号,T x y表示给x结点分配编号为y的任务. 分析 题目读起来就很有区间修改的味道,将一个区间变为一个值.问题在于怎么把这棵树对应到区间上. 对于一个结点,其控制的范围是它的子树,对应区间范围可以看作是以dfs序表示的区间.好像有点绕..就是给每个结点再对应一个dfs序,然后在dfs时把这个点控制的子树看

HDU 3397 线段树 双懒惰标记

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

HDU 1754 I Hate It(线段树之单点更新,区间最值)

I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 70863    Accepted Submission(s): 27424 Problem Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少. 这让很多学生很反感.不管你喜不喜欢,现在需要你做的是,就是按照老师的

Hdu 3966 Aragorn&#39;s Story (树链剖分 + 线段树区间更新)

题目链接: Hdu 3966 Aragorn's Story 题目描述: 给出一个树,每个节点都有一个权值,有三种操作: 1:( I, i, j, x ) 从i到j的路径上经过的节点全部都加上x: 2:( D, i, j, x ) 从i到j的路径上经过的节点全部都减去x: 3:(Q, x) 查询节点x的权值为多少? 解题思路: 可以用树链剖分对节点进行hash,然后用线段树维护(修改,查询),数据范围比较大,要对线段树进行区间更新 1 #include <cstdio> 2 #include

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