zoukankan      html  css  js  c++  java
  • HDU-3974 Assign the task(多叉树DFS时间戳建线段树)

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

    Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

    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

    题意:

    公司中有N个职员,只有一个老板,其余每个职员对应一个上司,这N个职员刚好组成一棵树。然后有M个操作。

    当给一个职员x分配任务y时(即 T y),x及其下属及其下属的下属都会放下手头的工作去完成任务y。对于每次询问(即x),程序输出职员x正在进行什么任务。

    简而言之:给出一个有向多叉树,初始所有节点为-1.有两种操作,一种为(T,x,y),表示将x节点及其的所有子树中的节点变为y,另一种为(C,x),为求x节点的值。

    题解:

    这道题的难点就在于如何将题中的对应关系转化为线段树的模型,在于如何处理好多叉树和线段树间的映射关系。

    线段树的本质就是对一整段连续区间进行操作。所以这道题的关键就在于清楚怎么将对多叉树的操作转化成对一整段连续区间的操作。

    很明显该公司的所有员工间的关系可以用一颗多叉树来表示。然后从公司老板(也就是入度为0的点)出发,用dfs给这棵树打上时间戳,确定每个点的影响范围并记录下来。

    根据新分配的id号码将其节点对应映射到线段树上面。这样分配任务就相当于更新一段连续的节点,查询任务相当于单点查询。

    代码如下:

      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <iostream>
      4 #include <string>
      5 #include <math.h>
      6 #include <algorithm>
      7 #include <vector>
      8 #include <queue>
      9 #include <set>
     10 #include <stack>
     11 #include <map>
     12 #include <math.h>
     13 const int INF=0x3f3f3f3f;
     14 typedef long long LL;
     15 const int mod=1e9+7;
     16 //const double PI=acos(-1);
     17 const int maxn=1e5+10;
     18 using namespace std;
     19 //ios::sync_with_stdio(false);
     20 //    cin.tie(NULL);
     21 
     22 struct Edge_node
     23 {
     24     int v;
     25     int next;
     26 }Edge[50005*2];
     27 
     28 struct SegTree_node
     29 {
     30     int l;
     31     int r;
     32     int num;
     33 }SegTree[50005<<2];
     34 int n,m;
     35 int cnt;//边的计数器,从0开始 
     36 int num;//线段树序号的计数器,从1开始 
     37 int head[50005];
     38 int vis[50005];//是否有上司,即入度为0 
     39 int st[50005];//开始遍历时的编号,同时作为线段树中的序号 
     40 int ed[50005];//遍历结束后的序号,表示该点在线段树中可以影响的最后一个序号(即上司)
     41 
     42 void init()//初始化 
     43 {
     44     cnt=0;
     45     num=0; 
     46     memset(head,-1,sizeof(head));
     47     memset(st,0,sizeof(st));
     48     memset(ed,0,sizeof(ed));
     49     memset(Edge,0,sizeof(Edge));
     50     memset(vis,0,sizeof(vis));
     51 }
     52 
     53 void add_edge(int u,int v)
     54 {
     55     Edge[cnt].v=v;
     56     Edge[cnt].next=head[u];
     57     head[u]=cnt++; 
     58 }
     59 
     60 void DFS(int u)
     61 {
     62     num++;
     63     st[u]=num;
     64     for(int i=head[u];i!=-1;i=Edge[i].next)
     65     {
     66         DFS(Edge[i].v);
     67     }
     68     ed[u]=num;
     69 }
     70 
     71 void PushDown(int rt)
     72 {
     73     if(SegTree[rt].num!=-1)
     74     {
     75         SegTree[rt<<1].num=SegTree[rt<<1|1].num=SegTree[rt].num;
     76         SegTree[rt].num=-1;
     77     }
     78 }
     79 
     80 void Build(int l,int r,int rt)
     81 {
     82     SegTree[rt].l=l;
     83     SegTree[rt].r=r;
     84     SegTree[rt].num=-1;
     85     if(l==r)
     86         return ;
     87     int mid=(l+r)>>1;
     88     Build(l,mid,rt<<1);
     89     Build(mid+1,r,rt<<1|1);
     90 }
     91 
     92 void Update(int L,int R,int C,int rt)
     93 {
     94     int l=SegTree[rt].l;
     95     int r=SegTree[rt].r; 
     96     if(L<=l&&R>=r)
     97     {
     98         SegTree[rt].num=C;
     99         return ;
    100     }
    101     PushDown(rt);
    102     int mid=(l+r)>>1;
    103     if(L<=mid)
    104         Update(L,R,C,rt<<1);
    105     if(R>mid)
    106         Update(L,R,C,rt<<1|1);
    107 }
    108 
    109 int Query(int L,int rt)
    110 {
    111     int l=SegTree[rt].l;
    112     int r=SegTree[rt].r;
    113     if(l==r)
    114         return SegTree[rt].num;
    115     PushDown(rt);
    116     int mid=(l+r)>>1;
    117     if(L<=mid)
    118         Query(L,rt<<1);
    119     else if(L>mid)
    120         Query(L,rt<<1|1);
    121 }
    122 
    123 int main()
    124 {
    125     int T;
    126     scanf("%d",&T);
    127     for(int k=1;k<=T;k++)
    128     {
    129         printf("Case #%d:
    ",k);
    130         init();
    131         scanf("%d",&n);
    132         for(int i=1;i<n;i++)
    133         {
    134             int u,v;
    135             scanf("%d %d",&u,&v);
    136             vis[u]=1;
    137             add_edge(v,u);
    138         }
    139         for(int i=1;i<=n;i++)
    140         {
    141             if(!vis[i])
    142             {
    143                 DFS(i);
    144                 break;
    145             }
    146         }
    147         Build(1,num,1);
    148         scanf("%d",&m);
    149         for(int i=1;i<=m;i++)
    150         {
    151             char c[5];
    152             int x;
    153             scanf("%s %d",c,&x);
    154             if(c[0]=='C')
    155             {
    156                 printf("%d
    ",Query(st[x],1));
    157             } 
    158             else if(c[0]=='T')
    159             {
    160                 int t;
    161                 scanf("%d",&t);
    162                 //st[x]->ed[x]代表x及x的下属在线段树中的区间范围 
    163                 Update(st[x],ed[x],t,1);
    164             }
    165         }
    166     }
    167     return 0;
    168 }
  • 相关阅读:
    写作的益处
    【转载】德鲁克:激发我一生的七段经历
    PS如何删除灰色的自动切片
    其他经验博文分类链接
    LODOP单个简短问答(小页面无需拖动滚动条)
    LODOP导出excel的页眉页脚
    LODOP导出和写入excel测试
    LODOP导出Excel简短问答和相关博文
    Lodop导出excel带数字格式
    LODOP批量打印判断是否加入队列1
  • 原文地址:https://www.cnblogs.com/jiamian/p/11415980.html
Copyright © 2011-2022 走看看