您的位置:首页 > 其它

[JLOI2014]松鼠的新家 倍增LCA+树上差分

2017-12-11 18:08 399 查看
题目描述

题目

本来想写一道Tarjan的,结果发现这题倍增比较好写

这题主要要搞懂树上差分这东西(NOIP前这东西卡了我好久)

大概要注意的就是对于除了出发点以外的所有点都是重复算了的,所以最后要有-1操作

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=300010;
int f
[20],head
,a
,b
,dep
;
int now,n;
struct E{int to,next;}e[N<<1];
void build(int u,int v){e[++now].to=v;e[now].next=head[u];head[u]=now;}

void dfs1(int u,int fa)
{
f[u][0]=fa;
for(int i=1;f[u][i-1];i++) f[u][i]=f[f[u][i-1]][i-1];
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(v == fa) continue;
dep[v]=dep[u]+1;
dfs1(v,u);
}
}

int lca(int u,int v)
{
if(dep[u] > dep[v]) swap(u,v);
int d=dep[v]-dep[u];
for(int i=0;(1<<i) <= d;i++)
if((1<<i) & d) v=f[v][i];
if(u == v) return u;
for(int i=19;i >= 0;i--)
if(f[u][i] != f[v][i])
u=f[u][i],v=f[v][i];
return f[u][0];
}

int read(){
int out=0;char c=getchar();while(c > '9' || c < '0') c=getchar();
while(c >= '0' && c <= '9') {out=(out<<1)+(out<<3)+c-'0';c=getchar();}return out;
}

void init()
{
n=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<n;i++) {int u=read(),v=read();build(u,v);build(v,u);}
dfs1(1,0);
}

void dfs2(int u)
{
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(v == f[u][0]) continue;
dfs2(v);
b[u]+=b[v];
}
}

void solve()
{
for(int i=2;i<=n;i++)
{
int u=a[i-1],v=a[i],glca=lca(u,v);
b[u]++;b[v]++;b[f[glca][0]]--;b[glca]--;
}
dfs2(1);
for(int i=2;i<=n;i++) b[a[i]]--;
for(int i=1;i<=n;i++) printf("%d\n",b[i]);
}

int main()
{
init();
solve();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: