ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF1061E - Politics

2021-05-10 21:01:24  阅读:176  来源: 互联网

标签:pre 限制 int flow rd Politics dis CF1061E


CF1061E - Politics

题目大意

给定两棵有根树\(T_1,T_2\),节点均从\(1-n\)编号

对于节点\(i\),有权值\(a_i\),每个节点可以被选择一次

对于\(T_1,T_2\),有\(q_1,q_2\)条限制,每条限制了一个子树\(k\)内恰好有\(x\)个点被选择

求最大化选择的权值之和,或者确定不存在方案


分析

如果剥离树的结构考虑,让问题变成点集之和的限制

这是一个经典的无法处理的问题,或许可以单纯形试试看

那么考虑树的结构如何处理

我们认为一个点被选择会向祖先链上的点总和+1,这是一个链状更新

可以用一棵内向树描述,再将限制加在边上,就能够得到一个简单的网络流模型

然而边权无法限制满流(除非上下界网络流),而现在问题不仅带权,还同时涉及两棵树

因此引入费用是必须的

解决恰好为\(x\)的限制

考虑将有限制的边视作特殊,我们将这条边额外加上一个费用\(\infty\),最后从答案中减去

如果最优解中无法流满这些边,答案将\(<0\)


解决两棵树

Naive的思路,我们需要强制两棵树上同编号的点入流相同

经过长时间弱智的思考,这无法实现

于是想办法强制两个点入流不同

容易发现,对于被选个数的限制可以对称转化为限制未选个数

从源点\(S\)向\(i_0\)连一条流量为1的边,\(i_0\)流向\(i_1\)表示选择\(i\),流向\(i_2\)表示不选

将\(T_1\)建成选择点的限制,\(T_2\)建成不选点的限制即可


形式化的说,对于一个费用流,我们想要限制两条边\(flow_1=flow_2\)

即\(flow_1-flow_2=0\),这难以做到

但是我们可以限制\(flow_1+(-flow_2)=0\),或者说

\(flow_1+(w-flow_2)=w\)

并且将对于\(flow_2\)的限制转化为对\(w-flow_2\)的限制,此时额外建立一个点\(t\)

\(S\)向\(t\)连\((w,\infty)\),强制向\(t\)流满\(w\)的流量,然后再从\(t\)向\(flow_1,w-flow_2\)分流即可


\(\text{EK}\)费用流 QQ图片20210506190147.jpg

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef pair <int,int> Pii;
#define reg register
#define mp make_pair
#define pb push_back
#define Mod1(x) ((x>=P)&&(x-=P))
#define Mod2(x) ((x<0)&&(x+=P))
#define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }

char IO;
template <class T=int> T rd(){
	T s=0; int f=0;
	while(!isdigit(IO=getchar())) f|=IO=='-';
	do s=(s<<1)+(s<<3)+(IO^'0');
	while(isdigit(IO=getchar()));
	return f?-s:s;
}

const int N=1544,INF=1e9+7;

int n,m,d;
int a[N];
struct Edge{
	int to,nxt,w,c;
} e[N*4];
int head[N],ecnt=1;
void AddEdge(int u,int v,int w,int c){
	e[++ecnt]=(Edge){v,head[u],w,c};
	head[u]=ecnt;
}
void Link(int u,int v,int w,int c){ AddEdge(u,v,w,c),AddEdge(v,u,0,-c); }
int S=1,T=2,V=2;

ll ans=0;
struct Tree{
	vector <int> G[N];
	int Rt,sz[N],lim[N],fa[N];
	void dfs(int u,int f) {
		//cout<<"pre dfs "<<u<<endl;
		sz[u]=1,lim[u]=-1,fa[u]=f;
		for(int v:G[u]) if(v!=f) {
			dfs(v,u);
			sz[u]+=sz[v];
		}
	}
	void ReadTree(){
		rep(i,2,n){
			int u=rd(),v=rd();
			G[u].pb(v),G[v].pb(u);
		}
		dfs(Rt,0);
	}
	void ReadLimit(){
		rep(_,1,rd()) {
			int u=rd(),x=rd();
			//cout<<"$"<<sz[u]<<endl;
			if(sz[u]<x) puts("-1"),exit(0);
			lim[u]=x;
		}
	}
	void Init(int k){
		fa[Rt]=T-V;
		if(k==0) {
			rep(i,1,n) {
				Link(T+i,V+i,1,a[i]);
				if(~lim[i]) {
					ans-=1ll*lim[i]*INF;
					Link(V+i,V+fa[i],lim[i],INF);
				} else Link(V+i,V+fa[i],n,0);
			}
		} else {
			rep(i,1,n) {
				Link(T+i,V+i,1,0);
				if(~lim[i]) {
					ans-=1ll*(sz[i]-lim[i])*INF;
					Link(V+i,V+fa[i],sz[i]-lim[i],INF);
				} else Link(V+i,V+fa[i],n,0);
			}
		}
		V+=n;
	}
} Tr[2];

ll dis[N];
int vis[N],pre[N];
int SPFA(){
	static queue <int> que;
	rep(i,1,V) dis[i]=-1e18;
	que.push(S),dis[S]=0;
	while(!que.empty()) {
		int u=que.front(); que.pop();
		vis[u]=0;
		for(int i=head[u];i;i=e[i].nxt){
			int v=e[i].to,c=e[i].c;
			if(dis[v]>=dis[u]+c || !e[i].w) continue;
			dis[v]=dis[u]+e[i].c,pre[v]=i;
			//cout<<"$"<<u<<' '<<v<<' '<<e[i].c<<' '<<e[i].w<<endl;
			if(!vis[v]) vis[v]=1,que.push(v);
		}
	}
	return dis[T]>-1e18;
}

void EK(){
	while(SPFA()) {
		int w=INF;
		for(int u=T;pre[u];u=e[pre[u]^1].to) cmin(w,e[pre[u]].w);
		for(int u=T;pre[u];u=e[pre[u]^1].to) e[pre[u]].w-=w,e[pre[u]^1].w+=w;
		ans+=w*dis[T];
	}
}

int main(){
	n=rd(),Tr[0].Rt=rd(),Tr[1].Rt=rd();
	rep(i,1,n) Link(S,V+i,1,INF),ans-=INF;
	V+=n;
	rep(i,1,n) a[i]=rd();
	rep(i,0,1) Tr[i].ReadTree();
	rep(i,0,1) Tr[i].ReadLimit(),Tr[i].Init(i);
	EK();
	if(ans<0) puts("-1");
	else printf("%lld\n",ans);
}

标签:pre,限制,int,flow,rd,Politics,dis,CF1061E
来源: https://www.cnblogs.com/chasedeath/p/14752757.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有