线段树+dfs序(Apple Tree )(Assign the task )

线段树+dfs序

给定一棵n个节点的树,m次查询,每次查询需要求出某个节点深度为h的所有子节点。

作为预处理,首先将树的所有节点按深度保存起来,每个深度的所有节点用一个线性结构保存,每个深度的节点相对顺序要和前序遍历一致。

然后从树的根节点进行dfs,对于每个节点记录两个信息,一个是dfs进入该节点的时间戳in[id],另一个是dfs离开该节点的时间戳out[id]。

最后对于每次查询,求节点v在深度h的所有子节点,只需将深度为h并且dfs进入时间戳在in[v]和out[v]之间的所有节点都求出来即可。

Step 1:

如下图,可以看到,由于普通的树并不具有区间的性质,所以在考虑使用线段树作为解题思路时,需要对给定的数据进行转化,首先对这棵树进行一次dfs遍历,记录dfs序下每个点访问起始时间与结束时间,记录起始时间是前序遍历,结束时间是后序遍历,同时对这课树进行重标号。

Step 2:

如下图,DFS之后,那么树的每个节点就具有了区间的性质。

那么此时,每个节点对应了一个区间,而且可以看到,每个节点对应的区间正好“管辖”了它子树所有节点的区间,那么对点或子树的操作就转化为了对区间的操作。

例题一:

POJ-3321  Apple Tree

There is an apple tree outside of kaka‘s house. Every autumn, a lot of apples will grow in the tree. Kaka likes apple very much, so he has been carefully nurturing the big apple tree.

The tree has N forks which are connected by branches. Kaka numbers the forks by 1 to N and the root is always numbered by 1. Apples will grow on the forks and two apple won‘t grow on the same fork. kaka wants to know how many apples are there in a sub-tree, for his study of the produce ability of the apple tree.

The trouble is that a new apple may grow on an empty fork some time and kaka may pick an apple from the tree for his dessert. Can you help kaka?

Input

The first line contains an integer N (N ≤ 100,000) , which is the number of the forks in the tree.
The following N - 1 lines each contain two integers u and v, which means fork u and fork v are connected by a branch.
The next line contains an integer M (M ≤ 100,000).
The following M lines each contain a message which is either
"x" which means the existence of the apple on fork x has been changed. i.e. if there is an apple on the fork, then Kaka pick it; otherwise a new apple has grown on the empty fork.
or
"x" which means an inquiry for the number of apples in the sub-tree above the fork x, including the apple (if exists) on the fork x
Note the tree is full of apples at the beginning


Output

For every inquiry, output the correspond answer per line.


Sample Input

3
1 2
1 3
3
Q 1
C 2
Q 1

Sample Output

3
2题目大意: 一棵树上长了苹果,每一个树枝节点上有长苹果和不长苹果两种状态,两种操作,一种操作能够改变树枝上苹果的状态,另一种操作询问某一树枝节点一下的所有的苹果有多少。操作C:如果有苹果,则经过C操作变成没有,如果没有苹果,经过C操作变成有。
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6 const int maxn=100010;
  7 struct node{
  8     int to;
  9     int nex;
 10 }e[maxn<<2];
 11 int head[maxn<<2],v[maxn<<2],u[maxn<<2];
 12 int vis[maxn<<2],cnt,num;
 13 struct tree{
 14     int l;
 15     int r;
 16     int sum;
 17 }tree[maxn<<2];
 18 void init()
 19 {
 20     memset(vis,0,sizeof(vis));
 21     memset(head,-1,sizeof(head));
 22     cnt=0;
 23 }
 24 void dfs(int x)
 25 {
 26     ++num;
 27     v[x]=num;
 28     vis[x]=1;
 29     for(int i=head[x];i!=-1;i=e[i].nex)
 30     {
 31         int t=e[i].to;
 32         if(vis[t]==1)
 33             continue;
 34         dfs(t);
 35     }
 36     u[x]=num;
 37 }
 38 void add(int x,int y)
 39 {
 40     e[cnt].to=y;
 41     e[cnt].nex=head[x];
 42     head[x]=cnt++;
 43 }
 44 void pushup(int cur)
 45 {
 46     tree[cur].sum=tree[cur<<1].sum+tree[cur<<1|1].sum;
 47 }
 48 void build(int l,int r,int cur)
 49 {
 50     tree[cur].l=l;
 51     tree[cur].r=r;
 52     if(l==r)
 53     {
 54         tree[cur].sum=1;
 55         return;
 56     }
 57     int mid=(l+r)/2;
 58     build(l,mid,cur<<1);
 59     build(mid+1,r,cur<<1|1);
 60     pushup(cur);
 61 }
 62 void update(int val,int cur)
 63 {
 64     if(tree[cur].l==tree[cur].r)
 65     {
 66         if(tree[cur].sum==0)
 67         {
 68             tree[cur].sum=1;
 69             return;
 70         }
 71         else
 72         {
 73             tree[cur].sum=0;
 74             return;
 75         }
 76     }
 77     int mid=(tree[cur].l+tree[cur].r)/2;
 78     if(val<=mid)
 79         update(val,cur<<1);
 80     if(val>=mid+1)
 81         update(val,cur<<1|1);
 82     pushup(cur);
 83 }
 84 int query(int pl,int pr,int cur)
 85 {
 86     if(pl<=tree[cur].l&&tree[cur].r<=pr)
 87     {
 88         return tree[cur].sum;
 89     }
 90     int ans=0;
 91     int mid=(tree[cur].l+tree[cur].r)/2;
 92     if(pl<=mid)
 93         ans+=query(pl,pr,cur<<1);
 94     if(pr>=mid+1)
 95         ans+=query(pl,pr,cur<<1|1);
 96     return ans;
 97 }
 98 int main()
 99 {
100     int n,m;
101     int a,b;
102     while(~scanf("%d",&n)&&n)
103     {
104         init();
105         num=0;
106         for(int i=1;i<=n-1;i++)
107         {
108             scanf("%d%d",&a,&b);
109             add(a,b);
110         }
111         dfs(1);
112         char s[5];
113         build(1,n,1);
114         scanf("%d",&m);
115         while(m--)
116         {
117             scanf("%s%d",s,&a);
118             if(s[0]==‘C‘)
119             {
120                 update(v[a],1);
121             }
122             if(s[0]==‘Q‘)
123             {
124                 printf("%d\n",query(v[a],u[a],1));
125             }
126         }
127     }
128 }

HDU-3974   Assign the task

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.

InputThe 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)OutputFor 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
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6 const int maxn=50010;
  7 struct node{
  8     int to;
  9     int nex;
 10 }e[maxn<<2];
 11 int head[maxn<<2],v[maxn<<2],u[maxn<<2];
 12 int vis[maxn<<2],cnt,num,in[maxn<<2];
 13 struct tree{
 14     int l;
 15     int r;
 16     int sum;
 17     int laz;
 18 }tree[maxn<<3];
 19 void init()
 20 {
 21     memset(tree,0,sizeof(tree));
 22     memset(e,0,sizeof(e));
 23     memset(v,0,sizeof(v));
 24     memset(u,0,sizeof(u));
 25     memset(in,0,sizeof(in));
 26     memset(vis,0,sizeof(vis));
 27     memset(head,-1,sizeof(head));
 28     cnt=0;
 29 }
 30 void dfs(int x)
 31 {
 32     ++num;
 33     v[x]=num;
 34     vis[x]=1;
 35     for(int i=head[x];i!=-1;i=e[i].nex)
 36     {
 37         int t=e[i].to;
 38         if(vis[t]==1)
 39             continue;
 40         dfs(t);
 41     }
 42     u[x]=num;
 43 }
 44 void add(int x,int y)
 45 {
 46     e[cnt].to=y;
 47     e[cnt].nex=head[x];
 48     head[x]=cnt++;
 49 }
 50 void pushdown(int cur)
 51 {
 52     if(tree[cur].laz!=0)
 53     {
 54         tree[cur<<1].laz=tree[cur<<1|1].laz=tree[cur].laz;
 55         tree[cur<<1].sum=tree[cur<<1|1].sum=tree[cur].laz;
 56         tree[cur].laz=0;
 57     }
 58     return;
 59 }
 60
 61 void build(int l,int r,int cur)
 62 {
 63     tree[cur].l=l;
 64     tree[cur].r=r;
 65     tree[cur].laz=0;
 66     tree[cur].sum=0;
 67     if(l==r)
 68     {
 69         return;
 70     }
 71     int mid=(l+r)/2;
 72     build(l,mid,cur<<1);
 73     build(mid+1,r,cur<<1|1);
 74 }
 75 void update(int pl,int pr,int num,int cur)
 76 {
 77     if(pl<=tree[cur].l&&tree[cur].r<=pr)
 78     {
 79         tree[cur].laz=num;
 80         tree[cur].sum=num;
 81         return;
 82     }
 83     pushdown(cur);
 84     int mid=(tree[cur].l+tree[cur].r)/2;
 85     if(pl<=mid)
 86         update(pl,pr,num,cur<<1);
 87     if(pr>=mid+1)
 88         update(pl,pr,num,cur<<1|1);
 89 }
 90 int query(int pl,int pr,int cur)//一定要注意query中不能缺少pushdown
 91 {
 92     if(pl<=tree[cur].l&&tree[cur].r<=pr)
 93     {
 94         return tree[cur].sum;
 95     }
 96     //int ans=0;
 97     pushdown(cur);
 98     int mid=(tree[cur].l+tree[cur].r)/2;
 99     if(pl<=mid)
100         return query(pl,pr,cur<<1);
101     if(pr>=mid+1)
102         return query(pl,pr,cur<<1|1);
103 }
104 int main()
105 {
106     int T;
107     int n,m;
108     int a,b;
109     cin>>T;
110     int id=1;
111     while(T--)
112     {
113         num=0;
114         init();
115         scanf("%d",&n);
116         for(int i=1;i<=n-1;i++)
117         {
118             scanf("%d%d",&a,&b);
119             add(b,a);
120             in[a]++;
121         }
122         for(int i=1;i<=n;i++)
123         {
124             if(in[i]==0)
125             {
126                 dfs(i);
127                 break;
128             }
129         }
130         char s[5];
131         build(1,n,1);printf("Case #%d:\n",id++);
132         scanf("%d",&m);
133         while(m--)
134         {
135             scanf("%s",s);
136             if(s[0]==‘C‘)
137             {
138                 scanf("%d",&a);
139                 int ans=query(v[a],u[a],1);
140                 if(ans==0)
141                 printf("-1\n");
142                 else
143                 printf("%d\n",ans);
144             }
145             if(s[0]==‘T‘)
146             {
147                 scanf("%d%d",&a,&b);
148                 update(v[a],u[a],b,1);
149             }
150         }
151     }
152 }

参考博客:

https://blog.csdn.net/qq_24489717/article/details/50569644

原文地址:https://www.cnblogs.com/1013star/p/9451019.html

时间: 2024-12-23 12:29:02

线段树+dfs序(Apple Tree )(Assign the task )的相关文章

Tsinsen A1505. 树(张闻涛) 倍增LCA,可持久化线段树,DFS序

题目:http://www.tsinsen.com/A1505 A1505. 树(张闻涛) 时间限制:1.0s   内存限制:512.0MB 总提交次数:196   AC次数:65   平均分:58.62 将本题分享到: 查看未格式化的试题   提交   试题讨论 试题来源 2013中国国家集训队第二次作业 问题描述 给定一棵N个节点的树,每个点有一个权值,有M个询问(a,b,c)若a 为1,回答b到c路径上的最小权值,若a为2,回答b到c路径上的最大权值,若a为3,回答b到c路径上的所有权值的

Codeforces 384E 线段树+dfs序

题目链接:点击打开链接 题意: 给定n个点,m个询问的无向树(1为根) 下面n个数表示每个点的权值 下面n-1行给出树 操作1:x点权值+v, x的第 i & 1 的儿子-v, 第 !(i&1) 的儿子+v 操作2:询问x点权值 dfs把树转成序列 根据深度把点分成2组 分别用线段树维护.. 然后Y一下 #include<stdio.h> #include<string.h> #include<iostream> #include<algorith

HDU 5692 线段树+dfs序

Snacks Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1779    Accepted Submission(s): 427 Problem Description 百度科技园内有n 个零食机,零食机之间通过n−1 条路相互连通.每个零食机都有一个值v ,表示为小度熊提供零食的价值. 由于零食被频繁的消耗和补充,零食机的价值v

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

题意:给一颗树,两种操作,查询 i 结点的颜色,和将i结点和它的子树都染成另一种颜色 题解:dfs序构建线段树,对于x和其子树染色就是 l[x] 和 r[x]; dfs序线段树板子 #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<cmath> #include<queue>

hdu 3974 Assign the task 线段树 DFS序

给你一棵树,每次修改一个子树的所有值,然后单点查询. 按照DFS序把节点排列(即在DFS中出现的先后次序),同一个子树在序列中连续. 1 #include <cstdio> 2 using namespace std; 3 typedef long long ll; 4 int n,q,T,Tc,cnt,sum; 5 int col[210000],lzy[210000],sta[51000],fin[51000]; 6 int nxt[51000],to[51000],head[51000]

HDU5692(线段树+dfs序)

Snacks Time Limit:5000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Description 百度科技园内有n个零食机,零食机之间通过n−1条路相互连通.每个零食机都有一个值v,表示为小度熊提供零食的价值. 由于零食被频繁的消耗和补充,零食机的价值v会时常发生变化.小度熊只能从编号为0的零食机出发,并且每个零食机至多经过一次.另外,小度熊会对某个零食机的零食有所偏爱,要求

【BZOJ-3779】重组病毒 LinkCutTree + 线段树 + DFS序

3779: 重组病毒 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 224  Solved: 95[Submit][Status][Discuss] Description 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力极强.为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病毒.实验在一个封闭的局域网内进行.局域网内有n台计算机,编号为1~n.一些计算机之间通过网线直接相连,形

【BZOJ-3306】树 线段树 + DFS序

3306: 树 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 792  Solved: 262[Submit][Status][Discuss] Description 给定一棵大小为 n 的有根点权树,支持以下操作: • 换根 • 修改点权      • 查询子树最小值 Input 第一行两个整数 n, Q ,分别表示树的大小和操作数. 接下来n行,每行两个整数f,v,第i+1行的两个数表示点i的父亲和点i的权.保证f < i.如 果f = 0

洛谷P2982 [USACO10FEB]慢下来Slowing down(线段树 DFS序 区间增减 单点查询)

To 洛谷.2982 慢下来Slowing down 题目描述 Every day each of Farmer John's N (1 <= N <= 100,000) cows conveniently numbered 1..N move from the barn to her private pasture. The pastures are organized as a tree, with the barn being on pasture 1. Exactly N-1 cow