[藍橋杯] 青出於藍勝於藍

題目描述:

無。

題目分析:

就是求一個節點子樹裏有多少個節點編號比這個數小,直接權值線段樹動態開點線段樹合併就好了。

題目鏈接:

題目

AC代碼:

#include <iostream>
#include <cstdio>
const int maxm=110000;
int ans[maxm],root[maxm];
int head[maxm],net[maxm*2],to[maxm*2];
int cnt,n,m;
inline void addedge(int u,int v){to[++cnt]=v,net[cnt]=head[u],head[u]=cnt;}
struct seg{
	int ls[maxm*40],rs[maxm*40];
	int sum[maxm*40];
	int sz;
	void insert(int &now,int l,int r,int ind)
	{
		if(!now) now=++sz;
		if(l>=r)
		{
			sum[now]=1;
			return;
		}
		int mid=(l+r)>>1;
		ind<=mid?insert(ls[now],l,mid,ind):insert(rs[now],mid+1,r,ind);
		sum[now]=sum[ls[now]]+sum[rs[now]];
	}
	int merge(int x,int y)
    {
    	if(!x||!y) return x+y;
    	ls[x]=merge(ls[x],ls[y]);
    	rs[x]=merge(rs[x],rs[y]);
    	sum[x]=sum[ls[x]]+sum[rs[x]];
    	return x;
    }
	int ask(int now,int l,int r,int ql,int qr)
    {
        if(!now) return 0;
        if(ql<=l&&r<=qr) return sum[now];
        int mid=(l+r)>>1;
        int res=0;
        if(ql<=mid) res+=ask(ls[now],l,mid,ql,qr);
        if(qr>mid) res+=ask(rs[now],mid+1,r,ql,qr);
        return res;
    }
}s;
void dfs(int now,int fa)
{
	for(int i=head[now];i;i=net[i])
	if(to[i]!=fa)
	{
		dfs(to[i],now);
		root[now]=s.merge(root[now],root[to[i]]);
	}
	ans[now]=s.ask(root[now],1,n,1,now-1);
	s.insert(root[now],1,n,now);
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<n;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		addedge(u,v);
		addedge(v,u);
	}
	dfs(m,0);
	for(int i=1;i<=n;i++)
	{
		printf("%d",ans[i]);
		if(i!=n) printf(" ");
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章