[题解]CF1009F Dominant Indices

CF1009F

很明显的\(dp\)方程:

\(dp_{u,i}=\sum dp_{v,i-1}\)

然而空间和时间上都过不去,于是我们需要考虑优化。

我们可以用动态开点线段树来维护这个\(dp\)数组:

对于每个节点都开一棵以深度为下标的线段树,叶节点维护的是当前子树中深度(注意这里不是距离了)为\(i\)的节点数,而非叶节点维护区间中叶节点信息的最大值。(线段树以深度为下标是因为合并是节点维护的区间应该对应)

这时我们就可以进行深度优先遍历,先处理儿子,再将儿子上的线段树合并到当前节点。处理完所有儿子之后就可以到当前节点的线段树上查 询答案。

查询答案时就可以采用一个很简单的贪心策略:左儿子的值大于等于右儿子则向左儿子查询,否则向右儿子查询,到叶节点则直接返回。不过 此时查询到的答案是深度而题目要求的是距离,因此我们需要将答案减去当前节点的深度。

代码:

#include <cstdio>

using namespace std;

#define re register
#define il inline
#define isdigit(ch) (ch>=48&&ch<=57)

const int N=1000010;

il void read(int &x)
{
	x=0;char ch=getchar();
	while(!isdigit(ch)) ch=getchar();
	while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
}
il void write(int x){if(x/10)write(x/10);putchar(x%10+48);}
//IO优化

#define max(a,b) (a>b?a:b)

int cnt,h[N];
struct edge{int v,nxt;}e[N<<1];
il void add(int u,int v){e[++cnt]=(edge){v,h[u]};h[u]=cnt;}
//链式前向星

int n;

int rt[N],pool;
int ls[N<<5],rs[N<<5],val[N<<5];
//val表示当前节点维护的深度区间中最大的节点数量
#define update(p) (val[p]=max(val[ls[p]],val[rs[p]]))
//更新节点信息
il int merge(int p,int q,int l,int r)
{
	if(!p||!q) return q|p;
	if(l==r){val[p]+=val[q];return p;}
	re int mid=(l+r)>>1;
	ls[p]=merge(ls[p],ls[q],l,mid);
	rs[p]=merge(rs[p],rs[q],mid+1,r);
	update(p);return p;
}
//合并线段树
il void insert(int &p,int l,int r,int x)
{
	if(!p) p=++pool;
	if(l==r){++val[p];return;}
	re int mid=(l+r)>>1;
	if(x>mid) insert(rs[p],mid+1,r,x);
	else insert(ls[p],l,mid,x);
	update(p);
}
il int query(int p,int l,int r)
{
	if(l==r) return l;
	re int mid=(l+r)>>1;
	if(val[ls[p]]<val[rs[p]]) return query(rs[p],mid+1,r);
	else return query(ls[p],l,mid);
}
//查询答案
int ans[N],dep[N];
il void dfs(int x,int fa)
{
	dep[x]=dep[fa]+1;
	insert(rt[x],1,n,dep[x]);
	for(re int i=h[x];i;i=e[i].nxt)
		if(e[i].v^fa)//if(e[i].v!=fa)
		{
			dfs(e[i].v,x);
			rt[x]=merge(rt[x],rt[e[i].v],1,n);
		}
	ans[x]=query(rt[x],1,n)-dep[x];
    //由于答案是要当前节点往下的距离,而query返回的是深度,因此要减去dep[x]
}

int main()
{
	read(n);
	for(re int i=1,u,v;i<n;++i)
	{
		read(u),read(v);
		add(u,v);add(v,u);
	}
	dfs(1,0);
	for(re int i=1;i<=n;++i)
		write(ans[i]),puts("");
	return 0;
}
posted @ 2020-12-26 09:47  watermonster1y1  阅读(62)  评论(0编辑  收藏  举报