P5996 题解

P5996

网络流。同 P2762 太空飞行计划问题 建图方式,将物品与 \(s\)\((s,i,v_i)\),警察与 \(t\)\((j+n,t,v_j)\),警察与对应的物品连 \((i,j+n,inf)\),答案为所有物品的收益和减最小割。割 \(s,i,v_i\) 表示不选物品,收益减 \(v_i\);割 \(j+n,t,v_j\) 表示贿赂警察,收益减 \(v_j\);警察与对应的物品的连边永远不被割,表示要么放弃物品要么贿赂警察。

\(n,m\leq 10^5\),显然跑不了网络流。考虑模拟最大流。

首先要描述警察 \(j\) 与物品 \(i\) 的关系。要满足:

\[\mid \frac{x_i-x_j}{y_i-y_j} \mid \leq \frac{w}{h} \]

\[x_j\times h-y_j\times w\leq x_i\times h-y_i\times w \]

\[x_j\times h+y_j\times w\geq x_i\times h+y_i\times w \]

\(x=x\times h+y\times w,y=x\times h-y\times w\)。得到 \(x_i\leq x_j,y_i\geq y_j\) ,能很好描述。

将物品和警察放在一起从左到右,从上到下考虑,自然满足 \(x_i\leq x_j\)。贪心,一个警察 \(j\) 的流优先从 \(y_i\geq y_j\)\(y_i\) 最小处流过来,因为更大的 \(y_i\) 能满足更多人限制。用 set 储存物品,警察处 lower_bound 查找。set 的 erase 函数会返回删去的值的下一个的迭代器。

code

int n,m,w,h,ans;
struct nd{
	int x,y,v,op;
}a[maxn];
bool cmp(nd u,nd v){
	if(u.x!=v.x)return u.x<v.x;
	return u.y>v.y;
}
set<pii> s;
void work(){
	n=read();m=read();w=read();h=read();
	for(int i=1;i<=n;i++){
		int u=read(),v=read(),val=read();
		a[i]={u*h+v*w,u*h-v*w,val,1};ans+=a[i].v;
	}
	for(int i=1;i<=m;i++){
		int u=read(),v=read(),val=read();
		a[i+n]={u*h+v*w,u*h-v*w,val,0};
	}
	sort(a+1,a+n+m+1,cmp);
	for(int i=1;i<=n+m;i++){
		if(a[i].op)s.insert({a[i].y,a[i].v});
		else{
			auto it=s.lower_bound({a[i].y,0});
			while(a[i].v){
				if(it==s.end())break;
				pii p=*it;it=s.erase(it);
				int d=min(a[i].v,p.second);
				a[i].v-=d;p.second-=d;ans-=d;
				if(p.second)s.insert(p);
			}
		}
	}
	printf("%lld\n",ans);
}
posted @ 2024-05-10 20:04  yhddd  阅读(14)  评论(0)    收藏  举报