• HDU-3974 Assign the task题解报告【dfs序+线段树】


    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



    题目大意:
    有N个人有着上司下属关系【一棵树】。开始每个人的任务是-1,当一个人分到一个任务时,他的下属也同时分到这个任务【即这个节点一下所有节点都被重新赋值为新值】。要求支持两种操作:
    C x y  询问x号当前的任务
    T x y 将任务y交给x号

    题解:
    这个问题就是整棵子树赋值的问题。如果暴力赋值会超时,能不能像线段树一样打个懒标记?但我们询问节点不想线段树一样是从上到下询问的,也就是说这个懒标记无法下传。怎么办?

    那我们就将树改为序列。
    怎么做呢?
    考虑一下树的dfs遍历的dfs序:在访问u节点后,它的儿子节点的dfs序一定在它之后并且时连续的,那么我们就可以利用dfs序化树为序列。
    在分配任务时,只需将[dfn[u],dfn[u]+siz-1]这个区间赋值就好了【siz是以u为根的子树的大小】

    然后就是套线段树模板了。由于只询问单点,所以非叶节点的值大可随意搞搞,但别溢出了= =
    【还有。别忘了每次初始化= =】

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int maxn=50005,INF=200000000;
    
    inline int read(){
    	int out=0,flag=1;char c=getchar();
    	while(c<48||c>57) {if(c=='-') flag=-1;c=getchar();}
    	while(c>=48&&c<=57) {out=out*10+c-48;c=getchar();}
    	return out*flag;
    }
    
    int N,M,L,R,num[4*maxn],lazy[4*maxn],index[maxn],root=1,siz=0;
    
    class node{
    	public:
    		int lson,rb,siz,f;
    		node() {lson=rb=0;siz=1;f=0;}
    }e[maxn];
    
    void preorder(int u){
    	index[u]=++siz;
    	for(int k=e[u].lson;k;k=e[k].rb){
    		preorder(k);
    		e[u].siz+=e[k].siz;
    	}
    }
    
    void init(){
    	memset(lazy,-1,sizeof(lazy));
    	memset(num,-1,sizeof(num));
    	siz=0;
    	root=1;
    	for(int i=0;i<=N;i++){e[i].lson=e[i].rb=e[i].f=0;e[i].siz=1;}
    	int T=N-1,a,f;
    	while(T--){
    		a=read();
    		f=read();
    		e[a].rb=e[f].lson;
    		e[a].f=f;
    		e[f].lson=a;
    	}
    	while(e[root].f) root=e[root].f;
    	preorder(root);
    }
    
    void pd(int u){
    	lazy[u<<1]=lazy[u<<1|1]=num[u<<1]=num[u<<1|1]=lazy[u];
    	lazy[u]=-1;
    }
    
    void Set(int u,int l,int r,int x){
    	if(l>=L&&r<=R) num[u]=lazy[u]=x;
    	else{
    		if(lazy[u]!=-1) pd(u);
    		int mid=(l+r)>>1;
    		if(mid>=L) Set(u<<1,l,mid,x);
    		if(mid<R) Set(u<<1|1,mid+1,r,x);
    		num[u]=x;
    	}
    }
    
    int Query(int u,int l,int r){
    	if(l==r) return num[u];
    	else{
    		if(lazy[u]!=-1) pd(u);
    		int mid=(l+r)>>1;
    		if(mid>=L) return Query(u<<1,l,mid);
    		else return Query(u<<1|1,mid+1,r);
    	}
    }
    
    int main()
    {
    	int T=read(),a,b;
    	char cmd;
    	for(int t=1;t<=T;t++){
    		printf("Case #%d:
    ",t);
    		N=read();
    		init();
    		M=read();
    		while(M--){
    			cmd=getchar();
    			while(cmd!='T'&&cmd!='C') cmd=getchar();
    			if(cmd=='T'){
    				a=read();
    				b=read();
    				L=index[a];
    				R=L+e[a].siz-1;
    				Set(1,1,N,b);
    			}
    			else{
    				L=R=index[read()];
    				printf("%d
    ",Query(1,1,N));
    			}
    		}
    	}
    	return 0;
    }
    

  • 相关阅读:
    转 Java高级程序员面试题
    发个说说0.0
    SpringMvc和servlet对比
    java面试数据类型
    java面试 关键字
    Ajax与传统Web开发的区别
    ssm框架常见问题
    浅谈C++多态性
    [转载]构造函数、析构函数可否声明为虚函数
    为什么不要在构造函数和析构函数中调用虚函数?
  • 原文地址:https://www.cnblogs.com/Mychael/p/8282899.html
Copyright © 2020-2023  润新知