可以费用流建图。
但是数据范围太大,那么记一下每个点相连的反向边的流量。
枚举lca就相当于模拟费用流找一条最短的增广路
树高log,复杂度就是 O(nlogn)
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=100010;
int n,m,c[N],p[N];
int g[N];
ll f[N];
int e[N][2];
inline void Up(int p){
if(c[p]) f[p]=0,g[p]=p; else f[p]=1<<30;
if((p<<1)<=n && f[p<<1]+(e[p<<1][0]?-1:1)<f[p])
f[p]=f[p<<1]+(e[p<<1][0]?-1:1),g[p]=g[p<<1];
if((p<<1|1)<=n && f[p<<1|1]+(e[p<<1|1][0]?-1:1)<f[p])
f[p]=f[p<<1|1]+(e[p<<1|1][0]?-1:1),g[p]=g[p<<1|1];
}
void dfs(int x){
if((x<<1)<=n) dfs(x<<1);
if((x<<1|1)<=n) dfs(x<<1|1);
Up(x);
}
ll ans=0;
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&c[i]);
dfs(1);
for(int i=1,x;i<=m;i++){
scanf("%d",&x);
int p=g[x],q=x; ll imax=f[x];
for(int j=x>>1,dis=e[x][1]?-1:1;j;dis+=e[j][1]?-1:1,j>>=1)
if(f[j]+dis<imax) imax=f[j]+dis,p=g[j],q=j;
ans+=imax; c[p]--;
for(int j=p;j!=q;j>>=1)
if(e[j][0]) e[j][0]--; else e[j][1]++;
for(int j=x;j!=q;j>>=1)
if(e[j][1]) e[j][1]--; else e[j][0]++;
for(int j=p;j;j>>=1) Up(j);
for(int j=x;j;j>>=1) Up(j);
printf("%lld ",ans);
}
return 0;
}