hdu 3974 树转换为线段+线段树

题意:

一个n个结点的有根无向树,给一个结点染色就相当于给这个结点及其子树染色。共进行m次染色和查询操作。

n <= 5e4 , m <= 5e4。

题解:

1.把树转换为线段:通过dfs把每个结点标记一个遍历到该结点的时间,类似于Tarjan。然后每个结点及其子树的时间都是一段连续的区间。并且统计出每个结点及其子树的数目。第x个结点对应的位置为pos[x],第x个结点及其子树共有cnt[x]个,第x个结点及其子树所在区间为[pos[x] , pos[x] + cnt[x]]。

2.注意:遍历的时候把[l,r]区间染成的颜色为y1,需记录当时时刻t1,且无需往子线段传递这个信息。当在t2时刻把[l,r]的某一子线段染成y2时,若t1 < t2,则查询时[l,r]的颜色传递不到子线段,反之传递给子线段。

#include<bits/stdc++.h>
#define N 50005
#define inf 0x3f3f3f3f
using namespace std ;
int n ;
int color[N << 2] ;
int pos[N] , cnt[N] ;
bool in[N] ;
vector <int> edge[N] ;
int m ;
int change[N << 2] ;
int change_num ;
int x , y ;
void init()
{
    int i ;
    memset(in , 0 , sizeof(in)) ;
    memset(pos , 0 , sizeof(pos)) ;
    memset(cnt , 0 , sizeof(cnt)) ;
    memset(color , -1 , sizeof(color)) ;
    memset(change , -1 , sizeof(change)) ;
    m = 0 ;
    change_num = 0 ;
    for(i = 1 ; i <= n ; i ++)
        edge[i].clear() ;
}
int dfs(int u)
{
    int i , j ;
    int v ;
    m ++ ;
    pos[u] = m ;
    cnt[u] = 1 ;
    for(i = 0 ; i < edge[u].size() ; i ++)
    {
        v = edge[u][i] ;
        cnt[u] += dfs(v) ;
    }
    return cnt[u] ;
}
void update()
{
    color[pos[x]] = y ;
    change[pos[x]] = ++ change_num ;
}
int query(int u)
{
    int v ;
    int i , j ;
    if(u == x)
       return color[pos[x]] ;
    for(i = 0 ; i < edge[u].size() ; i ++)
    {
        v = edge[u][i] ;
        if(pos[v] <= pos[x] && pos[x] <= pos[v] + cnt[v] - 1)
        {
          if(change[pos[u]] > change[pos[v]])
          {
             color[pos[v]] = color[pos[u]] ;
             change[pos[v]] = change[pos[u]] ;
          }
          return query(v) ;
        }
    }
}
int main()
{
    int t , case_t = 0 ;
    int i , j ;
    int u , v ;
    int root ;
    int num ;
    char s[10] ;
    scanf("%d" , &t) ;
    while(t --)
    {
        scanf("%d" , &n) ;
        init() ;
        for(i = 1 ; i <= n - 1 ; i ++)
        {
            scanf("%d%d" , &u , &v) ;
            edge[v].push_back(u) ;
            in[u] = 1 ;
        }
        for(i = 1 ; i <= n ; i ++)
            if(in[i] == 0)
            {
               root = i ;
               dfs(i) ;
               break ;
            }
        scanf("%d" , &num) ;
        printf("Case #%d:\n" , ++ case_t) ;
        while(num --)
        {
            scanf("%s" , s) ;
            if(s[0] == 'C')
            {
                scanf("%d" , &x) ;
                printf("%d\n" , query(root)) ;
            }
            else
            {
                scanf("%d%d" , &x , &y) ;
                update() ;
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/Irving0323/article/details/88374833