传送门:https://www.luogu.org/problemnew/show/P3258
咱们都知道树上查分+lca妙用太多了,这要是真的考到了,咋推得出来呢?
也许语文没学好,输入全错了,然过了样例(样例太水了,哇啦哇啦,交之后0分了3回-_-
那就积累一波吧::用本来确定的知识然后进行一些改动!!!
例如加减一些确定的ans
而不是先考虑自创算法啊~毕竟对树上差分都是囫囵吞枣地学。。。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
inline int wread(){
char c=getchar ();int flag=1,wans=0;
while (c<'0'||c>'9'){if (c=='-') flag=-1;c=getchar ();}
while (c>='0'&&c<='9'){wans=wans*10+c-'0';c=getchar ();}
return wans*=flag;
}
inline void OUT (int x){
if (x>9) OUT(x/10);
putchar (x%10+'0');
}
int n;
int a[300006],b[300006];
int K,hed[300006];
struct node{int v,nxt;}e[600005];
inline void ad (int u,int v){
e[++K]=(node){v,hed[u]};hed[u]=K;
}
int p[300005][21];
int dep[300005];
int ans[300005];
void dfs (int x,int fa){
p[x][0]=fa;
for (register int i(1);i<=20;++i) p[x][i]=p[p[x][i-1]][i-1];
for (register int i(hed[x]);i!=-1;i=e[i].nxt){
int v(e[i].v);
if (v==fa) continue;
dep[v]=dep[x]+1;
dfs (v,x);
}
return ;
}
int lca (int a,int b){
if (dep[a]>dep[b]) swap (a,b);
for (register int i(20);i>=0;--i)
if (dep[a]<=dep[p[b][i]]) b=p[b][i];
if (a==b) return a;
for (register int i(20);i>=0;--i){
if (p[a][i] == p[b][i]) continue;
a=p[a][i];b=p[b][i];
}
return p[a][0];
}
void getans (int x,int fa){
for (register int i(hed[x]);i!=-1;i=e[i].nxt){
int v(e[i].v);
if (v==fa) continue;
getans(v,x);
ans[x]+=ans[v];
}
return ;
}
int main (){
memset (hed,-1,sizeof hed);
n=wread();
for (register int i(1);i<=n;++i)
a[i]=wread();
for (register int i(1);i<n;++i){
int u(wread()),v(wread());
ad (u,v);ad(v,u);
}
dep[1]=1;
dfs (1,0);
for (register int i(1);i<n;++i){
int lcai(lca(a[i],a[i+1]));
ans[a[i]]++;
ans[a[i+1]]++;
ans[lcai]--;
ans[p[lcai][0]]--;
//覆盖i~i+1路径上所有的点
//包括i和i+1
//显然会重复,于是后面减回来
}
getans (1,0);
for (int i(2);i<=n;++i)
ans[a[i]]--;//减去多加上的&最后一个a[n](因为最后一个到了餐厅,不用糖果)
for (int i(1);i<=n;++i){
OUT(ans[i]);putchar ('\n');
}
return 0;
}