HDU--3887[Counting Offspring] DFS标号+线段树O(N*logN)

25 篇文章 0 订阅
18 篇文章 0 订阅
 

思路:
(1):dfs对每个点标号。记录每个点的开始时间S和结束时间E.
(2):按顺序一次查询并访问每个结点。
(3):查询并访问:

for(i=1;i<=N;i++)
{
	f[i]=Query(1,S1[i],E1[i]);
	Update(1,S1[i]);
}


 


注意:要数组模拟堆栈,不然会RE。

 

 

CODE:

/*DFS标号+线段树O(N*logN)*/
/*AC代码:859ms*/
#include <iostream>
#include <cstdio>
#include <memory.h>
#include <algorithm>
#define MAXN 200000
#define INF 1e8
#define lch(a) (a<<1)
#define rch(a) (a<<1|1)
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
using namespace std;
struct edge
{
	int u,v,next;
}E[MAXN];
int head[MAXN],ecnt;

struct Tree
{
	int s,e,num;
}Tnode[2*MAXN];

int S1[MAXN],E1[MAXN];
int f[MAXN],cur[MAXN];
int Stack[10000000];
bool vis[MAXN];
int N,P,top,cnt,num;

void Insert(int u,int v)
{
	E[ecnt].u=u;
	E[ecnt].v=v;
	E[ecnt].next=head[u];
	head[u]=ecnt++;
}

void Init()
{
	int i,u,v;
	memset(head,-1,sizeof(head));ecnt=0;
	for(i=1;i<N;i++)
	{
		scanf("%d%d",&u,&v);
		Insert(u,v);
		Insert(v,u);
	}
}
void Build(int p,int s,int e)
{
	Tnode[p].s=s;Tnode[p].e=e;Tnode[p].num=0;
	if(s==e) return;
	int mid=(s+e)>>1;
	Build(lch(p),s,mid);
	Build(rch(p),mid+1,e);
}
void Update(int p,int k)
{
	Tnode[p].num++;
	if(Tnode[p].s==Tnode[p].e)
		return;
	int mid=(Tnode[p].s+Tnode[p].e)>>1;
	if(k<=mid)
		Update(lch(p),k);
	else 
		Update(rch(p),k);
}
int Query(int p,int s,int e)
{
	if(Tnode[p].s==s&&Tnode[p].e==e)
		return Tnode[p].num;
	int mid=(Tnode[p].s+Tnode[p].e)>>1;
	if(e<=mid)
		return Query(lch(p),s,e);
	else if(s>mid)
		return Query(rch(p),s,e);
	else
		return Query(lch(p),s,mid)+Query(rch(p),mid+1,e);
}

void dfs()
{
	int i,u,v;
	memset(vis,false,sizeof(vis));
	for(i=1;i<=N;i++)
		cur[i]=head[i];
	top=num=0;
	Stack[++top]=P;
	while(top)
	{
		//printf("*\n");
		u=Stack[top];
		if(!vis[u])
		{
			S1[u]=++num;
			vis[u]=true;
		}
		for(;cur[u]!=-1;cur[u]=E[cur[u]].next)
		{
			v=E[cur[u]].v;
			if(vis[v]) continue;
			Stack[++top]=v;
			break;
		}
		//printf("*%d %d\n",Stack[top],u);
		if(Stack[top]==u)
		{
			E1[u]=++num;
			top--;
		}
	}
}

void Solve()
{
	int u,v,i;
	dfs();
	memset(f,0,sizeof(f));
	Build(1,1,2*N);
	for(i=1;i<=N;i++)
	{
		f[i]=Query(1,S1[i],E1[i]);
		//f[i]/=2;
		Update(1,S1[i]);
		//Update(1,E1[i]);
	}
	for(i=1;i<N;i++)
		printf("%d ",f[i]);
	printf("%d\n",f[i]);
}
int main()
{
	while(scanf("%d%d",&N,&P)!=EOF)
	{
		if(N==0&&P==0) break;
		Init();
		Solve();
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

__简言

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值