Assign the task---hdu3974(线段树优化+dfs)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3974

题意就是:公司有n个员工,关系有n-1个,T x y 代表把工作y交给员工x;

员工可以把工作交给下属;

本来是线段树的题,但是我真心看不懂,所以就找了个能看懂的方法了

 

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
#define N 50050

int f[N];
struct node
{
    int task, order;
}a[N];
int Query(int x)
{
    int order = -1, ans = -1;
    while(x != 0)
    {
        if(a[x].order > order)
        {
            ans = a[x].task;
            order = a[x].order;
        }
        x = f[x];
    }
    return ans;
}

int main()
{
    int T, n, m, t=1, x, y;
    char s[10];
    scanf("%d", &T);
    while(T--)
    {

        scanf("%d", &n);
        memset(a, -1, sizeof(a));
        memset(f, 0, sizeof(f));
        for(int i=1; i<=n-1; i++)
        {
            scanf("%d %d", &x, &y);
            f[x] = y;
        }
        scanf("%d", &m);
        printf("Case #%d:\n", t++);
        for(int i=1; i<=m; i++)
        {
            scanf("%s", s);
            if(s[0] == 'C')
            {
                scanf("%d", &x);
                printf("%d\n", Query(x));
            }
            else
            {
                scanf("%d %d", &x, &y);
                a[x].order = i;//工作的顺序;
                a[x].task = y;
            }
        }
    }
    return 0;
}
View Code

 看了学长的代码,有点理解了,就写了一下;

补充一下线段树的方法吧

可以用每个节点的所包含的子节点段来当做线段树的节点,查找每个节点所包含的段可以用简单的DFS实现。

 

#include<stdio.h>
#include<vector>
#include<iostream>
#include<string.h>
#include<algorithm>
#define N 50050
#define Lson r<<1
#define Rson r<<1|1
#define INF 0xfffffff
using namespace std;

int s[N], e[N], used[N], index;//s表示每个员工所有下属的开始和结束节点,包含本身
vector<int>G[N];

struct SegTree
{
    int L, R, task, vis;
    int mid()
    {
        return (L+R)>>1;
    }
    int len()
    {
        return R-L+1;
    }
}a[N<<2];
void dfs(int k)
{
    s[k]=++index;
    for(int i=0,len=G[k].size(); i<len; i++)
        dfs(G[k][i]);
    e[k]=index;
}
void BuildTree(int r, int L, int R)
{
    a[r].L =  L; a[r].R = R;
    a[r].task = -1; a[r].vis = 0;
    if(L == R)return ;

    BuildTree(Lson, L, a[r].mid());
    BuildTree(Rson, a[r].mid()+1,R);
}
void Down(int r)
{
    if(a[r].L != a[r].R && a[r].vis == 1)
    {
        a[Lson].vis = a[Rson].vis = 1;
        a[Lson].task = a[Rson].task = a[r].task;
        a[r].vis = 0;
    }
}
void Update(int r, int L, int R, int k)
{
    Down(r);
    if(a[r].L == L && a[r].R == R)
    {
        a[r].task = k;
        a[r].vis = 1;
        return;
    }

    if(R <= a[r].mid())
        Update(Lson, L, R, k);
    else if(L > a[r].mid())
        Update(Rson, L, R, k);
    else
    {
        Update(Lson, L, a[r].mid(), k);
        Update(Rson, a[r].mid()+1, R, k);
    }
}
int Query(int r, int k)
{
    Down(r);
    if(a[r].L == a[r].R)
        return a[r].task;
    if(k<=a[r].mid())
        return Query(Lson, k);
    else
        return Query(Rson, k);
}
int main()
{
    int T, t=1, n, m, x, y, u, v;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &n);
        memset(used, 0, sizeof(used));
        for(int i=0;i<=n;i++)
            G[i].clear();
        for(int i=1; i<n; i++)
        {
            scanf("%d %d", &u, &v);
            G[v].push_back(u);
            used[u] = 1;
        }
        index = 0;
        for(int i=1; i<=n; i++)
        {
            if(used[i]==0)
            {
                dfs(i);break;
            }
        }
        BuildTree(1, 1, n);
        printf("Case #%d:\n", t++);
        scanf("%d", &m);
        while(m--)
        {
            char str[5];
            scanf("%s", str);
            if(str[0]=='C')
            {
                scanf("%d", &x);
                printf("%d\n", Query(1,s[x]));
            }
            else
            {
                scanf("%d%d", &x, &y);
                Update(1, s[x], e[x], y);
            }
        }
    }
    return 0;
}
View Code

 很久之后的今天20160505再来看这道题,完全不是很难看懂的状态了

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
using namespace std;
typedef long long LL;
#define met(a, b) memset(a, b, sizeof(a))
#define N 50011
#define Lson r<<1
#define Rson r<<1|1

struct node
{
    int L, R, task, flag;///flag表示此区间是否被全部覆盖,如果是那么task表示此区间的工作是什么;
    int Mid(){ return (L+R)/2; }
    int Len(){ return (R-L+1); }
}a[N*4];

vector<vector<int> >G;
int s[N], e[N], du[N], Index;

void dfs(int u)
{
    s[u] = ++Index;///相当于是记录u得起始下属下标,结束下标在递归回来的时候确定的,
    int len = G[u].size();
    for(int i=0; i<len; i++)
        dfs(G[u][i]);
    e[u] = Index;
}

void Build(int r, int L, int R)
{
    a[r].L = L, a[r].R = R; a[r].task = -1;
    if( L == R )return;
    Build(Lson, L, a[r].Mid());
    Build(Rson, a[r].Mid()+1, R);
}

void Down(int r)
{
    if(a[r].flag && a[r].L != a[r].R)
    {
        a[Lson].flag = a[Rson].flag = a[r].flag;
        a[Lson].task = a[Rson].task = a[r].task;
        a[r].flag = 0;
    }
}

void Update(int r, int L, int R, int task)
{
    if(a[r].L == L && a[r].R == R)
    {
        a[r].flag = 1;
        a[r].task = task;
        return ;
    }
    Down(r);
    if( R <= a[r].Mid() )
        Update(Lson, L, R, task);
    else if( L > a[r].Mid() )
        Update(Rson, L, R, task);
    else
    {
        Update(Lson, L, a[r].Mid(), task);
        Update(Rson, a[r].Mid()+1, R, task);
    }
}
int Query(int r, int pos)
{
    Down(r);///因为上面也许没有更新到最底部,所以要再接着往下压;

    if(a[r].L == a[r].R)///找到叶子节点,并返回;
        return a[r].task;

    if(pos <= a[r].Mid())
        return Query(Lson, pos);
    else
        return Query(Rson, pos);
}

int main()
{
    int T, n, m, u, v, x, y, t = 1;
    scanf("%d", &T);
    while(T--)
    {
        met(du, 0); met(s, 0); met(e, 0);

        scanf("%d", &n);

        G.clear();
        G.resize(n+5);

        for(int i=1; i<n; i++)
        {
            scanf("%d %d", &u, &v);
            G[v].push_back(u);
            du[u] = 1;
        }
        Index = 0;
        for(int i=1; i<=n; i++)
        {
            if(!du[i])///找到根节点,然后按照递归的形式找到自己连续的下属;
            {
                dfs(i);break;
            }
        }
        Build(1, 1, n);
        scanf("%d", &m);
        printf("Case #%d:\n", t++);
        while(m--)
        {
            char ch[15];
            scanf("%s", ch);
            if(ch[0]=='T')
            {
                scanf("%d %d", &x, &y);
                Update(1, s[x], e[x], y);///更新的是x这个人的所有下属;
            }
            else
            {
                scanf("%d", &x);
                printf("%d\n", Query(1, s[x]));
            }
        }
    }
    return 0;
}
View Code

 

posted @ 2015-08-01 17:57  西瓜不懂柠檬的酸  Views(359)  Comments(0Edit  收藏  举报
levels of contents