#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
*/