[Neerc2016] Mole Tunnels - 模拟费用流

题目大意:
给你一颗高度log的二叉树,在上面做动态加点最小费用最大流(S连向某个点的流量+1)。
题解:
模拟维护费用流即可。暴力枚举向上跳几步,维护子树内距离最小的点(且该点有残量网络上到汇点的边)。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define N 100010
#define INF N
#define db long double
#define ull unsigned lint
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
	int x,ch;while((ch=gc)<'0'||ch>'9');
	x=ch^'0';while((ch=gc)>='0'&&ch<='9')
		x=(x<<1)+(x<<3)+(ch^'0');return x;
}
struct F{
	int val,id;
	F(int _v=0,int _i=0) { val=_v,id=_i; }
	inline bool operator<(const F &f)const { return val<f.val; }
	inline F operator+(int x) { return F(val+x,id); }
	inline int show() { return debug(val)sp,debug(id)ln,0; }
}f[N];int lc[N],rc[N],fa[N],c[N],frf[N];
inline int up(int x) { return frf[x]>0?-1:1; }
inline int down(int x) { return frf[x]<0?-1:1; }
inline int maintain(int x)
{
	f[x]=F(c[x]?0:INF,x);
	if(lc[x]) f[x]=min(f[x],f[lc[x]]+down(lc[x]));
	if(rc[x]) f[x]=min(f[x],f[rc[x]]+down(rc[x]));
	return 0;
}
int main()
{
	int n=inn(),m=inn();rep(i,1,n) c[i]=inn();
	rep(i,1,n) lc[i]=(i*2<=n?i*2:0),rc[i]=(i*2+1<=n?i*2+1:0),fa[i]=i>>1;
	for(int i=n;i;i--) maintain(i);
	for(int i=1,s=0;i<=m;i++)
	{
		int x=inn(),t=x;F val=f[x];
		for(int y=fa[x],v=up(x);y;v+=up(y),y=fa[y])
			if(f[y]+v<val) val=f[y]+v,t=y;
		int y=val.id;c[y]--,printf("%d ",s+=val.val);
		for(int z=x;z^t;z=fa[z]) frf[z]--;
		for(int z=y;z^t;z=fa[z]) frf[z]++;
		for(int z=x;z^t;z=fa[z]) maintain(z);
		for(int z=y;z^t;z=fa[z]) maintain(z);
		for(int z=t;z;z=fa[z]) maintain(z);
	}
	return !printf("\n");
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/83589297
今日推荐