HDU 3974 Assign the task 2011 Multi-University Training Contest 14 - Host by FZU 线段树

/*
题意:给定点的上下级关系,规定如果给i分配任务a,那么它所有的下属(直接或间接)都得放弃手上任务开始进行任务a
	给你一个序列,T a b,把任务b分配给a节点,C a 查询a正在进行的任务。
	
非常经典的线段树题目
   从树的根节点向下递归并对每个节点i按序编号为level[i].l,在遍历完所有i的子节点后记录i的编号最多子节点的编号为level[i].r
   此时level[i].l到level[i].r区间就是点i的覆盖区域(自身加所有子节点),给i分配任务就相当于对[level[i].l,level[i].r]操作
   这就可以用线段树处理了
	
	对于线段书某一个节点,用V记录它当前的任务,如果V==-1表示当前没有任务,对于查询a正在进行的任务,从根节点一直往下找,若
	查询过程中有节点i的区间覆盖a控制的区间并V>-1,这个任务就是要找的任务,因为i释放V后必定覆盖a的区间,现在V没有释放,表示V的
	子节点没有分配新的任务,所以V就是最新的任务
	
*/
#include <algorithm>
#include <iostream>
#include <cstdio>
#include<vector>
#include <cstring>
using namespace std;
const int N=50005;
int n,m,index;
int out[N];
struct Node
{
    int L,R,V;//区间的左端点和右端点及分配的任务
}nod[8*N];
void create(int t,int L,int R)//建树过程
{
    nod[t].L=L;
    nod[t].R=R;
    nod[t].V=-1;
    int mid=(L+R)>>1;
    if(L<R)
    {
        create(2*t,L,mid);
        create(2*t+1,mid+1,R);
    }
}
void down(int t)//向下释放任务
{
    if(nod[t].V==-1)return ;
    nod[2*t].V=nod[2*t+1].V=nod[t].V;
    nod[t].V=-1;
}
void insert(int t,int L,int R,int v)
{
    //cout<<"tt";
    int mid=(nod[t].L+nod[t].R)>>1;
    if(nod[t].L==L&&nod[t].R==R)
    {
        nod[t].V=v;
        return ;
    }
    down(t);
    if(R<=mid)insert(2*t,L,R,v);
    else if(L>mid)insert(2*t+1,L,R,v);
    else {insert(2*t,L,mid,v);insert(2*t+1,mid+1,R,v);}
}
int query(int t,int L)
{
    
    int mid=(nod[t].L+nod[t].R)>>1;
    if(nod[t].V>-1||(nod[t].L==nod[t].R))
    {
        return nod[t].V;
    }
    down(t);
    if(L<=mid)return query(2*t,L);
    else return query(2*t+1,L);
}
struct Level
{
    int l,r;
}level[N];
vector<int> node[N];
void dfs(int x)
{
    index++;
    level[x].l=index;
    int size=node[x].size();
    for(int i=0;i<size;i++)
    {
        dfs(node[x][i]);
    }
    level[x].r=index;
}
void init()
{
    scanf("%d",&n);
    index=0;
    int a,b;
    for(int i=0;i<=n;i++)
    {node[i].clear();
    out[i]=0;}
    for(int i=0;i<n-1;i++)
    {
    scanf("%d%d",&a,&b);
    out[a]++;
    node[b].push_back(a);
    }
    for(int i=1;i<=n;i++)
    if(out[i]==0)
    {
        dfs(i);
        break;
    }
    //cout<<index<<endl;
}
void solve(int ca)
{
    printf("Case #%d:\n",ca);
    //cout<<index<<endl;
    create(1,1,index);
    scanf("%d",&m);
    char s[2];
    int a,b;
    while(m--)
    {
        scanf("%s%d",s,&a);
        if(s[0]=='C')
        {
            printf("%d\n",query(1,level[a].l));
        }
        else 
        {
            scanf("%d",&b);
            insert(1,level[a].l,level[a].r,b);
        }
    }
}
int main()
{
    int ca;
    scanf("%d",&ca);
    for(int i=1;i<=ca;i++)
    {
        init();
        solve(i);
    }
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值