[JLOI2014] 松鼠的新家 (lca/树上差分)

[JLOI2014]松鼠的新家

题目描述

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

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

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

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

输入输出格式

输入格式:

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

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

输出格式:

一共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

Solution

树上差分中算比较裸的题了...

这道题是点差分(先要记住一个套路,点差分是在lca和其父节点-1,边差分将其转化到点上,在lca上-2)

for (int i=1;i<n;i++) {
     int lca=LCA(a[i],a[i+1]);
     cnt[a[i]]++, cnt[a[i+1]]++;
     cnt[lca]--, cnt[f[0][lca]]--;
}

然后dfs统计就可以了

但是如果仅仅这样的话,我们发现,从a[2]~a[n-1]我们都多统计了一次,所以要减回来,然后因为到了a[n]就停了,所以不要给a[n]准备,也要减

for (int i=2;i<=n;i++) cnt[a[i]]--;

就这样...没了

Code

#include<bits/stdc++.h>
#define in(i) (i=read())
using namespace std;

const int N=3e5+10;

int read() {
    int ans=0,f=1; char i=getchar();
    while(i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();}
    while(i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+(i^48),i=getchar();
    return ans*f;
}

int n,m,cur;
int head[N],nex[N<<1],to[N<<1];
int dep[N],f[25][N],cnt[N],lg[N]={-1},a[N];

void add(int a,int b) {
    to[++cur]=b,nex[cur]=head[a],head[a]=cur;
    to[++cur]=a,nex[cur]=head[b],head[b]=cur;
}

void init() {
    for (int i=1;i<=n;i++) lg[i]=lg[i>>1]+1;
    for (int i=1;i<=lg[n];i++)
        for (int j=1;j<=n;j++)
            f[i][j]=f[i-1][f[i-1][j]];
}

void dfs(int u) {
    for (int i=head[u];i;i=nex[i]) {
        if(to[i]==f[0][u]) continue;
        f[0][to[i]]=u, dep[to[i]]=dep[u]+1;
        dfs(to[i]);
    }
}

int LCA(int a,int b) {
    if(dep[a] > dep[b]) swap(a,b);
    int s=dep[b]-dep[a];
    for (int i=lg[s];i>=0;i--)
        if(s>>i&1) b=f[i][b];
    if(a==b) return a;
    for (int i=lg[n];i>=0;i--) {
        if(f[i][a]==f[i][b]) continue;
        a=f[i][a], b=f[i][b];
    }return f[0][a];
}

void find(int u) {
    for (int i=head[u];i;i=nex[i]) {
        if(to[i]==f[0][u]) continue;
        find(to[i]); cnt[u]+=cnt[to[i]];
    }
}

int main()
{
    in(n); for (int i=1;i<=n;i++) in(a[i]);
    for (int i=1,x,y;i<n;i++)
        in(x), in(y), add(x,y);
    dfs(1), init();
    for (int i=1;i<n;i++) {
        int lca=LCA(a[i],a[i+1]);
        cnt[a[i]]++, cnt[a[i+1]]++;
        cnt[lca]--, cnt[f[0][lca]]--;
    }
    find(1);
    for (int i=2;i<=n;i++) cnt[a[i]]--;
    for (int i=1;i<=n;i++) printf("%d\n",cnt[i]);
}
posted @ 2018-10-28 19:57  real_l  阅读(261)  评论(0编辑  收藏  举报