M_sea

洛谷3258 [JLOI2014]松鼠的新家
Luogu分析树上差分。对每条路径两端点+1,lca-1,lca的父节点-1。但是有些既是起点又是终点的节点多加了...
扫描右侧二维码阅读全文
31
2018/10

洛谷3258 [JLOI2014]松鼠的新家

Luogu

分析

树上差分。

对每条路径两端点+1,lca-1,lca的父节点-1。

但是有些既是起点又是终点的节点多加了一次,所以还要-1。

代码

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define re register
typedef int mainint;
#define int long long
using namespace std;

inline int read() {
    int X=0,w=1; char c=getchar();
    while (c<'0'||c>'9') { if (c=='-') w=-1; c=getchar(); }
    while (c>='0'&&c<='9') X=X*10+c-'0',c=getchar();
    return X*w;
}

const int MAXN=300000+10;

struct Edge { int v,nxt; };
Edge e[MAXN<<1];
int head[MAXN],cnt=0;

inline void addEdge(int u,int v) {
    e[++cnt].v=v,e[cnt].nxt=head[u],head[u]=cnt;
}

int dep[MAXN],f[MAXN][25];

inline void Dfs1(int u,int fa) {
    f[u][0]=fa;
    for (re int i=1;(1<<i)<=dep[u];++i)
        f[u][i]=f[f[u][i-1]][i-1];
    for (re int i=head[u];i;i=e[i].nxt) {
        int v=e[i].v;
        if (v==fa) continue;
        dep[v]=dep[u]+1;
        Dfs1(v,u);
    }
}
 
inline int LCA(int a,int b) {
    if (dep[a]<dep[b]) swap(a,b);
    for (re int i=19;~i;--i)
        if (dep[f[a][i]]>dep[b]) a=f[a][i];
    if (dep[a]!=dep[b]) a=f[a][0];
    for (re int i=19;~i;--i)
        if (f[a][i]!=f[b][i]) a=f[a][i],b=f[b][i];
    if (a!=b) a=f[a][0],b=f[b][0];
    return a;
}

int n;
int a[MAXN];
int s[MAXN];

inline void Dfs2(int u,int fa) {
    for (re int i=head[u];i;i=e[i].nxt) {
        int v=e[i].v;
        if (v==fa) continue;
        Dfs2(v,u); s[u]+=s[v];
    }
}

mainint main() {
    int n=read();
    for (re int i=1;i<=n;++i) a[i]=read();
    for (re int i=1,u,v;i<n;++i) {
        u=read(),v=read();
        addEdge(u,v); addEdge(v,u);
    }
    Dfs1(1,0);
    for (re int i=1;i<n;++i) {
        int x=a[i],y=a[i+1],lca=LCA(x,y);
        ++s[x],++s[y],--s[lca],--s[f[lca][0]];
    }
    Dfs2(1,0);
    for (re int i=1;i<=n;++i) printf("%lld\n",s[i]-(i!=a[1]));
    return 0;
}
最后修改:2018 年 11 月 09 日 06 : 04 PM

发表评论