Li Hua and Path题解
Li Hua and Path
令集合
集合
集合
那么答案就是
集合
考虑建出大根小根的点权重构树:
以大根为例,具体的构建方法为:从小到大枚举每个节点,考虑节点在原树上连向的其他节点,如果其他节点编号小于该节点,那么将其他节点所在子树的根连向该节点,并以该节点为父亲。
考虑点权重构树的性质(以大根为例):父亲的点权必然会大于儿子的点权,对于原树中
同样对于小根来说,对于原树中
所以我们就可以在小根重构树中枚举每个点
那么我们考虑新加入的点
上代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=4e5+50;
int n,m,ans,dfc;
int dep[N],fa[N],sz[N],st[N],ed[N];
int tr[N];
vector<int> mx[N],mn[N],e[N];
int lb(int x) {return x & -x;}
void add(int wz,int x) {while(wz<=n) tr[wz]+=x,wz+=lb(wz);}
int query(int wz) {int re=0;while(wz) re+=tr[wz],wz-=lb(wz);return re;}
int find(int u) {if(u!=fa[u]) return fa[u]=find(fa[u]);else return u;}
void merge(int u,int v)
{
u=find(u),v=find(v);
if(u==v) return ;
fa[v]=u;
}
void dfs1(int u)
{
sz[u]=1;
st[u]=++dfc;
for(int v:mx[u]) dfs1(v),sz[u]+=sz[v];
ans+=sz[u]-1;
ed[u]=dfc;
}
void dfs2(int u)
{
sz[u]=1;
for(int v:mn[u]) dep[v]=dep[u]+1,dfs2(v),sz[u]+=sz[v];
ans+=sz[u]-1;
}
void dfs3(int u)
{
ans-=2*(query(ed[u])-query(st[u]-1));
add(st[u],1);
for(int v:mn[u]) dfs3(v);
add(st[u],-1);
}
signed main()
{
scanf("%lld",&n);
for(int i=1,u,v;i<n;i++) scanf("%lld %lld",&u,&v),e[u].push_back(v),e[v].push_back(u);
for(int i=1;i<=n;i++) fa[i]=i;
for(int u=1;u<=n;u++)
for(int v:e[u]) if(v<u&&find(u)!=find(v))
mx[u].push_back(find(v)),merge(u,v);
for(int i=1;i<=n;i++) fa[i]=i;
dfs1(n);
for(int u=n;u>=1;u--)
for(int v:e[u]) if(v>u&&find(u)!=find(v))
mn[u].push_back(find(v)),merge(u,v);
dfs2(1);
dfs3(1);
printf("%lld\n",ans);
scanf("%lld",&m);
for(int i=1,u;i<=m;i++)
{
scanf("%lld",&u);
dep[n+i]=dep[u]+1;
ans+=n+i-dep[n+i]-1;
printf("%lld\n",ans);
}
return 0;
}