【题目链接】
https://www.lydsy.com/JudgeOnline/problem.php?id=4855
【题解】
考虑一个轻重路径剖分,当有一个新的节点被加入后,最多改变 O(log) O ( l o g ) 个路径的剖分。
那我们考虑时间倒流每次加入一个节点,那么改变的只可能是这个点到根的轻边,对于每个轻边,拿它与当前重边比较。比较时先比较size,再比较下一个节点插进来的时间。由于是时间倒流,所以时间晚的排名靠前。
时间复杂度 O(N∗log2N) O ( N ∗ l o g 2 N )
【代码】
/* --------------
user VanishD
problem bzoj-4855
----------------*/
# include
# define ll long long
# define inf 0x3f3f3f3f
# define N 200010
using namespace std;
int read(){
int tmp=0, fh=1; char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
return tmp*fh;
}
struct Edge{
int data, next;
}e[N*2];
struct Tree{
int pl, pr, l, r, size, ti, mx;
}T[N*3];
int size[N], per[N], head[N], place, num[N], q[N], up[N], id,
l[N], r[N], p[N], dad[N], tmp, ti[N], rt, k, n;
bool use[N], tag[N];
ll ans[N], sum, tot;
void build(int u, int v){
e[++place].data=v; e[place].next=head[u]; head[u]=place;
}
void dfs1(int x, int fa){
size[x]=1;
for (int ed=head[x]; ed!=0; ed=e[ed].next)
if (e[ed].data!=fa){
dfs1(e[ed].data,x);
if (size[per[x]]x]=e[ed].data;
size[x]=size[x]+size[e[ed].data];
}
}
void dfs2(int x, int fa, int an){
p[x]=++id; dad[p[x]]=p[fa]; up[p[x]]=p[an];
l[p[x]]=id;
if (per[x]!=0) dfs2(per[x],x,an);
for (int ed=head[x]; ed!=0; ed=e[ed].next)
if (e[ed].data!=fa&&e[ed].data!=per[x])
dfs2(e[ed].data,x,e[ed].data);
r[p[x]]=id;
}
void findelse(int x, int fa){
if (use[x]) return;
for (int ed=head[x]; ed!=0; ed=e[ed].next)
if (e[ed].data!=fa)
findelse(e[ed].data,x);
q[++tmp]=x;
}
void change(int p){
T[p].mx=max(T[T[p].pl].mx,T[T[p].pr].mx);
T[p].size=T[T[p].pl].size+T[T[p].pr].size;
T[p].ti=max(T[T[p].pl].ti,T[T[p].pr].ti);
}
int create(int l, int r){
int p=++place;
T[p].l=l, T[p].r=r;
if (T[p].l!=T[p].r){
int mid=(T[p].l+T[p].r)/2;
T[p].pl=create(l,mid);
T[p].pr=create(mid+1,r);
change(p);
}
else T[p].mx=l, T[p].size=0, T[p].ti=ti[l];
return p;
}
void modifysize(int p, int x){
if (T[p].l==T[p].r){
T[p].size+=1; return;
}
int mid=(T[p].l+T[p].r)/2;
if (mid>=x) modifysize(T[p].pl,x);
else modifysize(T[p].pr,x);
change(p);
}
int querysize(int p, int l, int r){
if (T[p].l==l&&T[p].r==r)
return T[p].size;
int mid=(T[p].l+T[p].r)/2;
if (mid>=r) return querysize(T[p].pl,l,r);
else if (midreturn querysize(T[p].pr,l,r);
else return querysize(T[p].pl,l,mid)+querysize(T[p].pr,mid+1,r);
}
void modifyti(int p, int x){
if (T[p].l==T[p].r){
T[p].ti=0; return;
}
int mid=(T[p].l+T[p].r)/2;
if (mid>=x) modifyti(T[p].pl,x);
else modifyti(T[p].pr,x);
change(p);
}
int queryti(int p, int l, int r){
if (T[p].l==l&&T[p].r==r)
return T[p].ti;
int mid=(T[p].l+T[p].r)/2;
if (mid>=r) return queryti(T[p].pl,l,r);
else if (midreturn queryti(T[p].pr,l,r);
else return max(queryti(T[p].pl,l,mid),queryti(T[p].pr,mid+1,r));
}
int querylight(int p, int l, int r){
if (T[p].l==l&&T[p].r==r) return T[p].mx;
int mid=(T[p].l+T[p].r)/2;
if (mid>=r) return querylight(T[p].pl,l,r);
else if (l>mid) return querylight(T[p].pr,l,r);
else {
int tmp=querylight(T[p].pr,mid+1,r);
if (tmp!=-1) return tmp;
return querylight(T[p].pl,l,mid);
}
}
void addlight(int p, int x, int tag){
if (T[p].l==T[p].r){
if (tag==1) T[p].mx=x;
else T[p].mx=-1;
return;
}
int mid=(T[p].l+T[p].r)/2;
if (mid>=x) addlight(T[p].pl,x,tag);
else addlight(T[p].pr,x,tag);
change(p);
}
void reget(int x, int ths){
if (x==0) return;
if (per[x]){
int size1=querysize(rt,l[per[x]],r[per[x]]), size2=querysize(rt,l[ths],r[ths]),
ti1=queryti(rt,l[per[x]],r[per[x]]), ti2=queryti(rt,l[ths],r[ths]);
if (size1x],1); addlight(rt,ths,0);
sum=sum+num[per[x]]-num[ths];
per[x]=ths;
}
}
else {
addlight(rt,ths,0);
sum=sum-num[ths];
per[x]=ths;
}
}
void extend(int x){
modifysize(rt,x);
modifyti(rt,x);
while (x!=0){
int flag=querylight(rt,up[x],x);
while (flag!=-1){
reget(dad[flag],flag);
if (flag==up[x]) break;
x=flag-1;
flag=querylight(rt,up[x],x);
}
x=dad[up[x]];
}
}
int main(){
n=read();
for (int i=1; i<=n; i++){
int u=read(), v=read(); tag[u]=true;
if (u!=0) build(i,u), build(u,i);
if (v!=0) build(i,v), build(v,i);
}
place=0;
dfs1(1,0); dfs2(1,0,1);
memset(per,0,sizeof(per));
for (int i=1; i<=n; i++){
num[p[i]]=i;
tot=tot+num[p[i]];
}
tmp=k=read();
for (int i=1; i<=tmp; i++){
q[i]=read();
use[q[i]]=true;
}
findelse(1,0);
for (int i=1; i<=n; i++)
q[i]=p[q[i]], ti[q[i]]=i;
memset(use,0,sizeof(use));
for (int i=1; i<=n; i++)
if (tag[i]) use[p[i]]=true;
for (int i=1; i<=n; i++) tag[i]=use[i];
rt=create(1,n); sum=tot;
for (int i=n; i>=1; i--){
extend(q[i]);
ans[i]=tot-sum;
}
for (int i=1; i<=k+1; i++)
printf("%lld\n",ans[i]);
return 0;
}