zoukankan      html  css  js  c++  java
  • [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
    ",cnt[i]);
    }
    
  • 相关阅读:
    构造方法
    不死神兔
    类与对象
    成员变量和局部变量的区别
    this关键字的理解
    private关键字理解
    如何设置客户端证书
    有关中文的正则表达式
    Web和证书服务:建立电子商务外部网
    认证服务Web 网页循序渐进指南
  • 原文地址:https://www.cnblogs.com/real-l/p/9866815.html
Copyright © 2011-2022 走看看