[Luogu P3258] [JLOI2014]松鼠的新家

洛谷传送门

题目描述

松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的。天哪,他居然真的住在”树“上。

松鼠想邀请小熊维尼前来参观,并且还指定一份参观指南,他希望维尼能够按照他的指南顺序,先去 a1 a 1 ,再去 a2 a 2 ,……,最后到 an a n ,去参观新家。可是这样会导致维尼重复走很多房间,懒惰的维尼不停地推辞。可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃。

维尼是个馋家伙,立马就答应了。现在松鼠希望知道为了保证维尼有糖果吃,他需要在每一个房间各放至少多少个糖果。

因为松鼠参观指南上的最后一个房间 an a n 是餐厅,餐厅里他准备了丰盛的大餐,所以当维尼在参观的最后到达餐厅时就不需要再拿糖果吃了。

输入输出格式

输入格式:

第一行一个整数n,表示房间个数第二行 n n 个整数,依次描述a1an

接下来 n1 n − 1 行,每行两个整数 x x y,表示标号 x x y的两个房间之间有树枝相连。

输出格式:

一共 n n 行,第i行输出标号为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);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值