hihocoder 1193 树堆

#1193 : 树堆
时间限制:20000ms
单点时限:2000ms
内存限制:256MB
描述
假定我们有一棵有根树,其中每个点上有权。它被称为树堆当且仅当每个点的权值都大于等于它的所有孩子。


现在我们有一棵有根树,它的每个点上有权。我们可以不断对它进行如下的操作:选择一个非根结点v,删除v,然后将v的所有孩子连到v的父亲上。


不断进行以上操作,此时可能一个子树会形成树堆。


对树上的每个结点x,求出以这种方式形成的以x为根的树堆中,结点最多的树堆的结点个数。


输入
第一行n,树上的点数。


第二行n个用空格分开的整数a0, ..., an - 1。ai为点i的权值。


下面n - 1行,每行两个整数x, y。表示x, y间有一条边。


树的根为0。1 ≤ n ≤ 1e5. 0 ≤ ai ≤ 1e9. 0 ≤ x, y ≤ n - 1. 保证输入形成一棵树。


输出
一行,n个用空格分开的整数。第i个表示以题目中描述的方式生成的以i - 1为根的树堆中,结点最多的树堆中的结点个数。

这题也是网上搜不到题解的题目

线段树合并,实现的时间复杂度n*logn*logn,应该有n*logn的解,但肯定都需要节点val值向下传递,代码难度增加.

线段树中存储的是当前节点最多能接多少节点于该值的后面

每加入一个父节点,设val为x,则可以接于x之后的最大节点数可以用于更新线段树>=x的部分.

#include <cstdio>
#include <map>
#include <set>
#include <vector>
#include <algorithm>
#pragma warning(disable:4996)
using namespace std;

int n;
const int bign = 100033;
const int bigm = 55 * bign;
vector<int> eelist[bign];
int w[bign];
int p[bign];
int rw[bign];
int croot[bign];
int ans[bign];
int myqueue[bigm];
int mlft[bigm];
int mrht[bigm];
int val[bigm];
const int qlen = 5000000;
int mfront, mtail;
int maxn = 0;

bool cmp(const int&nodeA, const int&nodeB)
{
	return (w[nodeA] < w[nodeB] || (nodeA < nodeB && w[nodeA] == w[nodeB]));
}

inline int newnode()
{
	int tmp = myqueue[mfront];
	mlft[tmp] = 0;
	mrht[tmp] = 0;
	mfront = (mfront + 1) % qlen;
	return tmp;
}

inline void mclear(int &tid)
{
	myqueue[mtail] = tid;
	mtail = (mtail + 1) % qlen;
}

int query(int mroot, int tid)
{
	int b1 = 1;
	int e1 = maxn;
	int troot = mroot;
	int ret = 0;
	while (troot)
	{
		int mid = (b1 + e1) >> 1;
		ret += val[troot];
		if (tid <= mid)
		{
			e1 = mid;
			troot = mlft[troot];
		}
		else
		{
			b1 = mid + 1;
			troot = mrht[troot];
		}
	}
	return ret;
}

int unite(int mroot1, int mroot2)
{
	if (mroot1 == 0 || mroot2 == 0)
		return mroot1 + mroot2;
	val[mroot1] += val[mroot2];
	
	mlft[mroot1] = unite(mlft[mroot1], mlft[mroot2]);
	mrht[mroot1] = unite(mrht[mroot1], mrht[mroot2]);

	mclear(mroot2);
	return mroot1;
}

int mupdate(int mroot, int b1, int e1, int l, int r)
{
	int mid = (b1 + e1) >> 1;
	if (mroot == 0)
		mroot = newnode();
	if (b1 == l && e1 == r)
	{
		val[mroot]++;
		return mroot;
	}

	if (r <= mid)
	{
		mlft[mroot] = mupdate(mlft[mroot], b1, mid, l, r);
	}
	else if(l > mid)
	{
		mrht[mroot] = mupdate(mrht[mroot], mid + 1, e1, l, r);
	}
	else
	{
		mlft[mroot] = mupdate(mlft[mroot], b1, mid, l, mid);
		mrht[mroot] = mupdate(mrht[mroot], mid + 1, e1, mid + 1, r);
	}
	return mroot;

}

void dfs(int u, int fa)
{
	croot[u] = 0;
	for (int i = 0; i < eelist[u].size(); i++)
	{
		int v = eelist[u][i];
		if (v != fa)
		{
			dfs(v, u);
			croot[u] = unite(croot[u], croot[v]);
		}
	}
	int x = query(croot[u], rw[u]);
	int b1 = rw[u];
	int e1 = maxn;
	while (b1 <= e1)
	{
		int mid = (b1 + e1) >> 1;
		if (query(croot[u], mid) > x)
		{
			e1 = mid - 1;
		}
		else
		{
			b1 = mid + 1;
		}
	}
	ans[u] = x + 1;

	croot[u] = mupdate(croot[u], 1, maxn, rw[u], e1);
}

int main()
{
	for (int i = 1; i <= (qlen-1); i++)
	{
		myqueue[mtail++] = i;
	}
	scanf("%d", &n);
	for (int i = 0; i < n; i++)
	{
		scanf("%d", &w[i]);
		p[i] = i;
	}
	sort(p, p + n, cmp);
	rw[p[0]] = 1;
	maxn = 1;
	
	for (int i = 1; i < n; i++)
	{
		if (w[p[i]] == w[p[i - 1]])
		{
			rw[p[i]] = rw[p[i - 1]];
 		}
		else
		{
			rw[p[i]] = rw[p[i - 1]] + 1;
		}
		maxn = rw[p[i]];
	}


	for (int i = 0; i < n - 1; i++)
	{
		int x, y;
		scanf("%d%d", &x, &y);
		eelist[x].push_back(y);
		eelist[y].push_back(x);
	}

	dfs(0, 0);
	for (int i = 0; i < n; i++)
		printf("%d%c", ans[i], (i == n - 1) ? '\n' : ' ');
}

/*
14
0 4 3 6 2 3 4 4 1 7 9 8 6 2
0 1
0 2
0 3
1 4
3 5
3 6
3 7
4 8
4 9
4 10
6 11
6 12
11 13
*/

猜你喜欢

转载自blog.csdn.net/dx888888/article/details/80247362