洛谷传送门
题目描述
松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的。天哪,他居然真的住在”树“上。
松鼠想邀请小熊维尼前来参观,并且还指定一份参观指南,他希望维尼能够按照他的指南顺序,先去 a1 a 1 ,再去 a2 a 2 ,……,最后到 an a n ,去参观新家。可是这样会导致维尼重复走很多房间,懒惰的维尼不停地推辞。可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃。
维尼是个馋家伙,立马就答应了。现在松鼠希望知道为了保证维尼有糖果吃,他需要在每一个房间各放至少多少个糖果。
因为松鼠参观指南上的最后一个房间 an a n 是餐厅,餐厅里他准备了丰盛的大餐,所以当维尼在参观的最后到达餐厅时就不需要再拿糖果吃了。
输入输出格式
输入格式:
第一行一个整数n,表示房间个数第二行 n n 个整数,依次描述
接下来 n−1 n − 1 行,每行两个整数 x x ,,表示标号 x x 和的两个房间之间有树枝相连。
输出格式:
一共 n n 行,第行输出标号为i的房间至少需要放多少个糖果,才能让维尼有糖果吃。
输入输出样例
输入样例#1:
5
1 4 5 3 2
1 2
2 4
2 3
4 5
输出样例#1:
1
2
1
2
1
说明
2<=n<=300000 2 <= n <= 300000
解题分析
一道比较裸的LCT, 不过300000已经达到LCT的极限了(有一个点博主T了一次)。
其实每次就是树上链的加减, 但要注意上一次的起点是这一次的终点, 所以要减去1。
具体实现见代码。
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <cstring>
#include <cstdlib>
#define R register
#define IN inline
#define gc getchar()
#define W while
#define ls tree[now].son[0]
#define rs tree[now].son[1]
#define dad tree[now].fat
#define MX 300005
template <class T>
IN void in (T &x)
{
x = 0; R char c = gc;
W (!isdigit(c)) c = gc;
W (isdigit(c))
x = (x << 1) + (x << 3) + c - 48, c = gc;
}
namespace LCT
{
struct Node
{
int son[2], fat, val, add;
bool rev;
}tree[MX];
int st[MX], ord[MX], top, dot;
IN bool get(const int &now) {return tree[dad].son[1] == now;}
IN bool nroot(const int &now) {return tree[dad].son[0] == now || tree[dad].son[1] == now;}
IN void pushadd(const int &now, const int &del) {tree[now].add += del, tree[now].val += del;}
IN void pushrev(const int &now) {std::swap(ls, rs); tree[now].rev ^= 1;}
IN void pushdown(const int &now)
{
if(tree[now].add)
{
if(ls) pushadd(ls, tree[now].add);
if(rs) pushadd(rs, tree[now].add);
tree[now].add = 0;
}
if(tree[now].rev)
{
if(ls) pushrev(ls);
if(rs) pushrev(rs);
tree[now].rev = false;
}
}
IN void rotate(const int &now)
{
R bool dir = get(now); R int fa = dad, grand = tree[fa].fat;
tree[fa].son[dir] = tree[now].son[dir ^ 1];
tree[tree[now].son[dir ^ 1]].fat = fa;
if(nroot(fa)) tree[grand].son[get(fa)] = now;
tree[now].fat = grand;
tree[fa].fat = now;
tree[now].son[dir ^ 1] = fa;
}
IN void splay(R int now)
{
R int fa, grand; int x = now;
st[top = 1] = now;
W (nroot(now)) st[++top] = now = dad;
W (top) pushdown(st[top--]);
now = x;
W (nroot(now))
{
fa = dad, grand = tree[fa].fat;
if(nroot(fa)) rotate(get(fa) == get(now) ? fa : now);
rotate(now);
}
}
IN void access(R int now)
{
for (R int x = 0; now; x = now, now = dad)
splay(now), rs = x;
}
IN void make_root(const int &now) {access(now), splay(now), pushrev(now);}
IN void split(const int &x, const int &y) {make_root(x), access(y), splay(y);}
IN void link(const int &x, const int &y) {make_root(x), tree[x].fat = y;}
}
using namespace LCT;
int main(void)
{
int a, b;
in(dot);
for (R int i = 1; i <= dot; ++i) in(ord[i]);
for (R int i = 1; i < dot; ++i)
{
in(a), in(b);
link(a, b);
}
tree[ord[1]].val++;
for (R int i = 1; i < dot; ++i)
{
split(ord[i + 1], ord[i]);
pushadd(tree[ord[i]].son[0], 1);
}
R int now;
tree[ord[dot]].val--;
for (R int i = 1; i <= dot; ++i)
{//最后只需要pushdown 即可, 不需要splay, 否则TLE
now = i;
st[top = 1] = i;
W (nroot(now)) st[++top] = now = dad;
W (top) pushdown(st[top--]);
printf("%d\n", tree[i].val);
}
}