Description
N
,
M
≤
3
e
6
N,M\le3e6
N,M≤3e6
Solution
求dfs序的时候爆栈了QUQ
考虑人和商品建点跑费用流,优化一下可能可以跑1e5?
观察我们费用流实际上在干什么,就是从一个子树内选出最大的权值然后把它取反。那么我们可以用线段树维护dfs序区间最大值来搞这个东西。由于直接做没法退流因此需要按照dfs序降序贪心
考虑到时限只有1s,nlogn要跑3e6,我们可以用桶排搞掉排序的一个log,然后记录叶子直接向上跳搞掉常数,这样卡一卡就可以过了
题解比较牛逼。我们把询问离线然后打标记,每做完一个节点就把这个节点缩到它父亲所在并查集。又短又快的标准做法
Code
// #pragma GCC optimize(3)
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#define rep(i,st,ed) for (register int i=st;i<=ed;++i)
#define drp(i,st,ed) for (register int i=st;i>=ed;--i)
typedef long long LL;
const int INF=0x3f3f3f3f;
const int N=3000005;
struct edge {int y,next;} e[N];
int pos[N],dfn[N],size[N];
int rec[N<<2],r[N],p[N],lxf[N],wjp[N];
int ls[N],fa[N],edCnt,ql,qr,n;
int queue[N];
char buffer[N],*S,*T;
inline char Get_Char() {
if(S==T) {
T=(S=buffer)+fread(buffer,1,N,stdin);
if(S==T) return EOF;
}
return *S++;
}
int read() {
char c; int re=0;
for(c=Get_Char();c<'0'||c>'9';c=Get_Char());
while(c>='0'&&c<='9') re=(re<<1)+(re<<3)+(c-'0'),c=Get_Char();
return re;
}
void add_edge(int x,int y) {
e[++edCnt]=(edge) {y,ls[x]}; ls[x]=edCnt;
}
void build(int now,int tl,int tr) {
if (tl==tr) return (void) (wjp[rec[now]=tl]=now);
int mid=(tl+tr)>>1;
build(now<<1,tl,mid),build(now<<1|1,mid+1,tr);
rec[now]=(dfn[rec[now<<1]]>dfn[rec[now<<1|1]])?rec[now<<1]:rec[now<<1|1];
}
int query(int now,int tl,int tr) {
if (tl>=ql&&tr<=qr) return rec[now];
int mid=(tl+tr)>>1,qx,qy;
qx=(ql<=mid)?query(now<<1,tl,mid):0;
qy=(mid+1<=qr)?qy=query(now<<1|1,mid+1,tr):0;
if (!qx||!qy) return qx+qy;
return (dfn[qx]>dfn[qy])?qx:qy;
}
void bfs() {
int head,tail;
queue[head=tail=1]=1;
for (;head<=tail;) {
int x=queue[head++];
for (int i=ls[x];i;i=e[i].next) queue[++tail]=e[i].y;
}
drp(ti,n,1) {
int x=queue[ti];
size[x]=1;
for (int i=ls[x];i;i=e[i].next) {
size[x]+=size[e[i].y];
}
}
int last=1; pos[1]=1;
rep(i,2,n) {
if (fa[queue[i]]!=fa[queue[i-1]]) last=pos[fa[queue[i]]];
else last+=size[queue[i-1]];
pos[queue[i]]=last+1;
}
rep(i,1,n) dfn[pos[i]]=i-1;
}
void dfs(int x) {
pos[x]=++pos[0],size[x]=1;
dfn[pos[0]]=x-1;
for (int i=ls[x];i;i=e[i].next) {
dfs(e[i].y); size[x]+=size[e[i].y];
}
}
bool cmp(int x,int y) {
return pos[x]>pos[y];
}
int main(void) {
n=read(); int m=read();
rep(i,2,n) {
fa[i]=read()+1;
add_edge(fa[i],i);
}
bfs(); build(1,1,n);
// dfs(1); build(1,1,n);
LL ans=0;
rep(i,1,m) r[i]=read()+1;
rep(i,1,m) lxf[pos[r[i]]]++;
drp(i,n,1) lxf[i]+=lxf[i+1];
int ggg=0;
rep(i,1,m) p[lxf[pos[r[i]]]--]=r[i];
ggg=0;
rep(i,1,m) {
int x=p[i];
ql=pos[x],qr=pos[x]+size[x]-1;
int res=query(1,1,n);
if (dfn[res]<=0) continue;
ans+=dfn[res]; dfn[res]=-dfn[res];
for (int now=wjp[res]>>1;now;now>>=1) {
rec[now]=(dfn[rec[now<<1]]>dfn[rec[now<<1|1]])?rec[now<<1]:rec[now<<1|1];
}
}
printf("%lld\n", ans);
return 0;
}