HDU3887 dfs序+线段树

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
思路:用线段树维护dfs序,线段树的结点1-n表示时间戳1-n而不是原来的序号。因为求f[i]的时候对i的遍历是从小到大的,就可以让遍历过的i为1,未遍历到的为0,这样每次先求i的子树中内序号小于i的结点个数就可以直接统计i时间戳范围内的1的个数,然后再将i更新为1

#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn=100005;
vector<int>g[maxn];
int n,p;
int s[maxn],e[maxn],dfsnum[maxn];
int ti;
struct Tree{
    int l, r, sum, add;
}tree[maxn<<2];
void dfs(int u,int fa)
{
    s[u]=++ti;
    dfsnum[ti]=u;
    for(int i=0;iif(g[u][i]==fa) continue;
        dfs(g[u][i],u);
    }
    e[u]=ti;
}


//延迟更新 
void pushup(int root){//儿子把信息传递给父亲
    if(tree[root].l==tree[root].r)return ;
    tree[root].sum=tree[root<<1].sum+tree[root<<1|1].sum;   //<<1:*2; <<1|1:*2+1
    return ;
}
 void pushdown(int root){//父亲把自己的信息传给儿子
    if(tree[root].l==tree[root].r)return ;
    if(tree[root].add==-1)return ;
    tree[root<<1].add=tree[root<<1|1].add=tree[root].add;
    tree[root<<1].sum=(tree[root<<1].r-tree[root<<1].l+1)*tree[root].add; //长度*父亲.add
    tree[root<<1|1].sum=(tree[root<<1|1].r-tree[root<<1|1].l+1)*tree[root].add;
    tree[root].add=-1;
    return ;
}
//初始化 
void build(int l,int r,int root){
    tree[root].l=l;
    tree[root].r=r;
    tree[root].sum=0;
    tree[root].add=-1;
    if(l==r){//直到单个区间位置
        tree[root].sum=0;
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,root<<1);//左区间
    build(mid+1,r,root<<1|1); //右区间
    pushup(root);//把儿子的信息更新到父亲
    return;
}
//更新区间 
void update(int l,int r,int z,int root){
    if(l==tree[root].l&&tree[root].r==r){
        tree[root].sum=(tree[root].r-tree[root].l+1)*z;
        tree[root].add=z;//把要更新的内容保存下来,等到要用儿子时                                    再去更新
        return ;
    }
    pushdown(root);//用父亲的信息更新儿子
    int mid=tree[root].l+tree[root].r>>1;
    if(r<=mid)update(l,r,z,root<<1);
    else if(l>mid)update(l,r,z,root<<1|1);
    else {
        update(l,mid,z,root<<1);
        update(mid+1,r,z,root<<1|1);
    }
    pushup(root);//更新父亲
    return ;
}
//查找区间信息 
int query(int l,int r,int root){
    if(l==tree[root].l&&tree[root].r==r){
        return tree[root].sum;
    }
    pushdown(root);
    int mid=tree[root].l+tree[root].r>>1;
    if(r<=mid)return query(l,r,root<<1);
    else if(l>mid)return query(l,r,root<<1|1);
    else return query(l,mid,root<<1)+query(mid+1,r,root<<1|1);
}
int main()
{
    while(~scanf("%d%d",&n,&p)&&n+p)
    {
        ti=0;
        for(int i=1;i<=n;i++) g[i].clear();
        for(int i=1;iint u,v;
            scanf("%d%d",&u,&v);
            g[u].push_back(v);
            g[v].push_back(u);
        }
        dfs(p,-1);
        build(1,n,1);
        for(int i=1;i<=n;i++)
        {
            printf("%d",query(s[i],e[i],1));
            if(i==n) printf("\n");else printf(" ");
            update(s[i],s[i],1,1);
        }
    }
    return 0;
} 

你可能感兴趣的:(HDU,Gloria,线段树,dfs序)