点差分
方法:在两端点+1,他们的lca-1,lca的父亲-1,即可消除影响。
#include<map>
#include<queue>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<deque>
using namespace std;
typedef long long ll;
const int maxm=300007;
int n,p,q;
int a[maxm];
int pre[2*maxm],last[maxm],other[2*maxm],l;
int jump[maxm][21],dep[maxm];
int sum[maxm];
void add(int x,int y)
{
l++;
pre[l]=last[x];
last[x]=l;
other[l]=y;
}
void dfs(int x)
{
for(int p=last[x];p;p=pre[p])
{
int v=other[p];
if(v==jump[x][0]) continue;
jump[v][0]=x;
dep[v]=dep[x]+1;
dfs(v);
}
}
void dfs1(int x)
{
for(int p=last[x];p;p=pre[p])
{
int v=other[p];
if(v==jump[x][0]) continue;
dfs1(v);
sum[x]+=sum[v];
}
}
int lca(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
for(int j=0;j<=19;j++)
{
if((dep[x]-dep[y])&(1<<j))
x=jump[x][j];
}
if(x==y) return x;
for(int j=19;j>=0;j--)
{
if(jump[x][j]!=jump[y][j])
{
x=jump[x][j];
y=jump[y][j];
}
}
return jump[x][0];
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",a+i);
for(int i=1;i<=n-1;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dfs(1);
for(int j=1;j<=19;j++)
{
for(int i=1;i<=n;i++)
jump[i][j]=jump[jump[i][j-1]][j-1];
}
for(int i=1;i<n;i++)
{
int u=a[i],v=a[i+1];
int lcc=lca(u,v);
sum[jump[u][0]]++;
sum[v]++;
sum[lcc]--;
sum[jump[lcc][0]]--;
}
dfs1(1);
sum[a[n]]--;
sum[a[1]]++;
for(int i=1;i<=n;i++)
printf("%d
",sum[i]);
return 0;
}