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

大致题意

有一家公司有N个员工(从1到N),公司里每个员工都有一个直接的老板(除了整个公司的领导)。如果你是某人的直接老板,那个人就是你的下属,他的所有下属也都是你的下属。如果你是没有人的老板,那么你就没有下属,没有直接老板的员工就是整个公司的领导,也就是说N个员工构成了一棵树。公司通常把一些任务分配给一些员工来完成,当一项任务分配给某个人时,他/她会把它分配给他/她的所有下属,换句话说,这个人和他/她的所有下属在同一时间接受了一项任务。此外,每当员工收到一个任务,他/她将停止当前任务(如果他/她有),并开始新的任务。在公司将某些任务分配给某个员工后,编写一个程序来帮助找出某个员工当前的任务。
Input
第一行包含单个正整数T(T<=10),表示测试用例的数量。对于每个测试用例:第一行包含一个整数N(N≤50,000),它是雇员的数目。下面的N-1行分别包含两个整数u和v,这意味着雇员v是雇员u的直接老板(1<=u,v<=N)。下一行包含一个整数M(M≤50,000)。下面的M行分别包含一条消息,“Cx”表示对员工x的当前任务的查询,“Tx y”表示公司将任务y分配给员工x。(1<=x<=N,0<=y<=10^9)

思路

每次修改一颗子树,容易想到是dfs序,然后就变成了线段树区间赋值,单点查询的题目。一个小坑点,query的时候第x个员工在线段树中的节点是in[x],不要写成x。

代码

这里是有根树,强调了父子关系,建单向边就行。
贴一下dfs序建线段树的代码。

#include<bits/stdc++.h>
using namespace std;
#define maxn 50005
#define maxm 20006
#define ll long long int
#define INF 0x3f3f3f3f
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,r,l) for(int i=r;i>=l;i--)
#define mem(a) memset(a,0,sizeof(a))
#define sqr(x) (x*x)
#define inf (ll)2e18+1
int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
     while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
     return f*x;
}
int T,n,m,in[maxn],out[maxn],t[maxn<<2],laz[maxn<<2],tim,du[maxn];
struct node{int v,nxt;}ed[maxn];
int head[maxn],tot;
void add(int x,int y){ed[++tot]={y,head[x]};head[x]=tot;}
void dfs(int x){
    in[x]=++tim;
    for(int i=head[x];i;i=ed[i].nxt){
        int v=ed[i].v;
        dfs(v);
    }
    out[x]=tim;
}
void pushdown(int x){
    t[x<<1]=t[x<<1|1]=laz[x<<1]=laz[x<<1|1]=laz[x];
    laz[x]=-1;
}
void update(int x,int l,int r,int lp,int rp,int v){
    if(r>l&&laz[x]!=-1)pushdown(x);
    if(lp<=l&&r<=rp){
        t[x]=laz[x]=v;
        return ;
    }
    int mid=(l+r)>>1;
    if(lp<=mid)update(x<<1,l,mid,lp,rp,v);
    if(mid+1<=rp)update(x<<1|1,mid+1,r,lp,rp,v);
}
int query(int x,int l,int r,int pos){
    if(r>l&&laz[x]!=-1)pushdown(x);
    if(l==r)return t[x];
    int mid=(l+r)>>1;
    if(pos<=mid)return query(x<<1,l,mid,pos);
    else return query(x<<1|1,mid+1,r,pos);
}
int main()
{
    int kase=0;
    T=read();
    while(T--){
        printf("Case #%d:\n",++kase);
        memset(laz,-1,sizeof(laz));
        memset(t,-1,sizeof(t));
        mem(head);mem(du);
        tot=tim=0;
        n=read();
        int x,y,rt;char s[2];
        inc(i,1,n-1){
            x=read();y=read();
            add(y,x);du[x]++;
        }
        inc(i,1,n)if(du[i]==0)rt=i;
        dfs(rt);
        m=read();
        while(m--){
            scanf("%s",s);
            if(s[0]=='C'){
                x=read();
                printf("%d\n",query(1,1,n,in[x]));///注意这里查询点x的时候 对应的线段树中的点是in[x]...
            }
            else {
                x=read();y=read();
                update(1,1,n,in[x],out[x],y);
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值