题意
求每一个点子树中标号比他小的节点数
思路
用DFS求出每一个点的 in,out ,x点的所有子节点就在in[x]到out[x]之间。建树时以每个点 in[ ]的值对应叶子结点(例如:in[3]=4,则树4~4区间所对应的叶子结点所表示标号的即为3)。查询时因为范围已经确定所以只需按照输出顺序查询就行,每查询一次就需要更新一次(把比这个数小的下标所对应的叶子结点加1(标记),每次查询时只需看看这个点的 in到out 区间有多少个标记即有多少个比他小的)
例如:
4 3
1 3
2 3
4 1
关系为
标号的关系
DFS以后:
in[3]=1 out[3]=4
in[1]=2 out[1]=3
in[4]=3 out[4]=3
in[2]=4 out[2]=4
建树
更新时,只更新in[x]~out[x]区间所对应的叶子结点,以及该叶子结点对应的所有父辈及父辈以上的节点。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=262144;
int in[maxn],out[maxn],sum[maxn];
vector<int>g[maxn/2];
int time;
void dfs(int x,int fa)
{
in[x]=++time;
for(int i=0;i<g[x].size();i++)
{
int cnt=g[x][i];
if(cnt==fa)
continue;
dfs(cnt,x);
}
out[x]=time;
}
void pushup(int rt)
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void bulid(int l,int r,int rt)
{
sum[rt]=0;
if(l==r)
return ;
int m=(l+r)>>1;
bulid(l,m,rt<<1);
bulid(m+1,r,rt<<1|1);
}
void update(int L,int l,int r,int rt)
{
if(l==r)
{
sum[rt]=1;
return ;
}
int m=(l+r)>>1;
if(L<=m)
update(L,l,m,rt<<1);
else
update(L,m+1,r,rt<<1|1);
pushup(rt);
}
int query(int L,int R,int l,int r,int rt)
{
if(L<=l && R>=r)
return sum[rt];
int cnt=0;
int m=(l+r)>>1;
if(L<=m)
cnt+=query(L,R,l,m,rt<<1);
if(R>m)
cnt+=query(L,R,m+1,r,rt<<1|1);
return cnt;
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m) && (n||m))
{
time=0;
int x,y;
for(int i=1;i<=n;i++)
g[i].clear();
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
}
dfs(m,0);
bulid(1,n,1);
for(int i=1;i<=n;i++)
{
printf("%d%c",query(in[i],out[i],1,n,1),i==n?'\n':' ');
update(in[i],1,n,1);
}
}
return 0;
}
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=262144;
int in[maxn],out[maxn],sum[maxn];
int time,ans,head[maxn];
struct node
{
int to,next;
}p[maxn];
void add(int u,int v)
{
p[ans]=node{v,head[u]};
head[u]=ans++;
}
void dfs(int x,int fa)
{
in[x]=++time;
for(int i=head[x];i!=-1;i=p[i].next)
{
int cnt=p[i].to;
if(cnt==fa)
continue;
dfs(cnt,x);
}
out[x]=time;
}
void pushup(int rt)
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void bulid(int l,int r,int rt)
{
sum[rt]=0;
if(l==r)
return ;
int m=(l+r)>>1;
bulid(l,m,rt<<1);
bulid(m+1,r,rt<<1|1);
}
void update(int L,int l,int r,int rt)
{
if(l==r)
{
sum[rt]=1;
return ;
}
int m=(l+r)>>1;
if(L<=m)
update(L,l,m,rt<<1);
else
update(L,m+1,r,rt<<1|1);
pushup(rt);
}
int query(int L,int R,int l,int r,int rt)
{
if(L<=l && R>=r)
return sum[rt];
int cnt=0;
int m=(l+r)>>1;
if(L<=m)
cnt+=query(L,R,l,m,rt<<1);
if(R>m)
cnt+=query(L,R,m+1,r,rt<<1|1);
return cnt;
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m) && (n||m))
{
time=ans=0;
memset(head,-1,sizeof(head));
int x,y;
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dfs(m,0);
bulid(1,n,1);
for(int i=1;i<=n;i++)
{
printf("%d%c",query(in[i],out[i],1,n,1),i==n?'\n':' ');
update(in[i],1,n,1);
}
}
return 0;
}