HDU 3887 Counting Offspring [DFS序列+树状数组]

HDU 3887 Counting Offspring [DFS序列+树状数组]

Counting Offspring

Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 423    Accepted Submission(s): 137


Problem Description
You are given a tree, it’s root is p, and the node is numbered from 1 to n. Now define f(i) as the number of nodes whose number is less than i in all the succeeding nodes of node i. Now we need to calculate f(i) for any possible i.
 

Input
Multiple cases (no more than 10), for each case:
The first line contains two integers n (0<n<=10^5) and p, representing this tree has n nodes, its root is p.
Following n-1 lines, each line has two integers, representing an edge in this tree.
The input terminates with two zeros.
 

Output
For each test case, output n integer in one line representing f(1), f(2) … f(n), separated by a space.
 

Sample Input
    
    
    
    
15 7 7 10 7 1 7 9 7 3 7 4 10 14 14 2 14 13 9 11 9 6 6 5 6 8 3 15 3 12 0 0
 

Sample Output
    
    
    
    
0 0 0 0 0 1 6 0 3 1 0 0 0 2 0
 

Author
bnugong
 

Source
2011 Multi-University Training Contest 5 - Host by BNU


题意是,给一棵树,给每个结点一个标号,问所有存在的结点,它的子树中,结点标号小于它的有多少个。

做法:DFS序列构造+树状数组查询区间。

竟然忘了DFS的遍历的意义。对一棵树进行DFS遍历,一个结点最多到达两次,一次出,一次入,而这之间的结点标号均为它的子树结点的标号。所以只要用某种方法快速查询其左右标号内含的区间中,比它小的标号个数即可。(别*2)在肖神的提携下,ym到了树状数组在本题的使用方法。

做法流程。初始化(记得树状数组和DFS记录序列要开点数*2的。。因为这个nc半天,不解释。) ->建图-> DFS(因为HDU坑爹的栈大小,必须手写栈模拟DFS才能过。。第一次手工模拟DFS。。太蛋疼了。。调了无数次。)->对于每个点查询DFS序列。(既然是离线查询,那么就按照从小到大查吧。凡事要有个序,有序了就好查了。对于每个点的标号,先查它的左右区间是否有比它小的sum(r[i] - 1) - sum(l[i]]).....再把它插入树状数组中,插一次就好,不然结果还得除二。(都是肖神!)
T_T。。记得树状数组和dfs序列都是开到点数*2的,而其他的都是点数大小的。注意初始化和树状数组查询和更新时的范围同理。
代码:
#include  < iostream >
#include 
< cstdio >
#include 
< cstring >
#include 
< stack >
#include 
< algorithm >
using   namespace  std;
stack 
< int >  S;
#define  maxn 100005
int  cnt,p,n,tot,lit[maxn],seq[maxn  *   2 ],l[maxn],r[maxn],tr[maxn  *   2 ];
int  bit( int  x){ return  x  &   - x;}
bool  vis[maxn];
struct  edge
{
    
int  p,next;
    edge(){}
    edge(
int  a, int  b):p(a),next(b){}
}v[maxn],e[maxn 
*   2 ];
void  add( int  p, int  q)
{
    e[tot] 
=  edge(q,v[p].next);
    v[p].next 
=  tot ++ ;
}
int  sum( int  x)
{
    
int  ans  =   0 ;
    
for (;x  >   0 ;x  -=  bit(x))
        ans 
+=  tr[x];
    
return  ans;
}
void  mod( int  x, int  val)
{
    
for (;x  <  cnt;x  +=  bit(x))
        tr[x] 
+=  val;    
}
void  init()
{
    tot 
=   0 ;
    
for ( int  i  =   1 ;i  <=  n;i ++ )
        v[i].next 
=   - 1 ;
    fill(tr,tr 
+   2   *  n  +   1 , 0 );
    fill(vis,vis 
+  n  +   1 , 0 );
    
while ( ! S.empty())
        S.pop();
}
void  dfs()
{
    cnt 
=   1 ;
    S.push(p);
    
while ( ! S.empty())
    {
        
int  now  =  S.top();
        
if ( ! vis[now])
        {
            seq[cnt] 
=  now;
            l[now] 
=  cnt ++ ;
            vis[now] 
=   true ;
        }
        
bool  mark  =   false ;
        
for ( int  k  =  v[now].next; ~ k;k  =  e[k].next)
        {
            
if ( ! vis[e[k].p])
            {
                mark 
=   true ;
                S.push(e[k].p);
                v[now].next 
=  e[k].next;
                
break ;
            }
        }
        
if (mark)
            
continue ;
        
if (vis[now])
        {
            seq[cnt] 
=  now;
            r[now] 
=  cnt ++ ;
            S.pop();
        }
    }
}
void  gao()
{
    
for ( int  i  =   1 ;i  <=  n;i ++ )
    {
        lit[i] 
=  sum(r[i]  -   1 -  sum(l[i]);
        mod(l[i],
1 );
    }
}
int  main()
{
    
while (scanf( " %d %d " , & n, & p)  ==   2   &&  (p  ||  n))
    {
        init();
        
for ( int  i  =   0 ;i  <  n  -   1 ;i ++ )
        {
            
int  a,b;
            scanf(
" %d %d " , & a, & b);
            add(a,b);
            add(b,a);
        }
        dfs();
        gao();
        
for ( int  i  =   1 ;i  <=  n;i ++ )
        {
            printf(
" %d " ,lit[i]);
            putchar((i 
==  n) ? ' \n ' : '   ' );
        }
    }
}
Down

你可能感兴趣的:(HDU 3887 Counting Offspring [DFS序列+树状数组])