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;
}