博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
CF786E ALT
阅读量:6853 次
发布时间:2019-06-26

本文共 3096 字,大约阅读时间需要 10 分钟。

题目大意

给一颗n个节点的树,每个边上有一个守卫。有m个居民,每个居民有一个散步路径(两个节点的树上最短路)。一个居民高兴当且仅当他获得了一个宠物或者他散步的路径上所有的守卫都有宠物。求最少需要几个宠物能让所有居民高兴。输出方案。

n,m <= 20000

输入格式:

第一行两个整数,n和m

接下来n-1行,每行两个整数,代表一条边

接下来m行,每行两个整数,代表一个居民的路径端点。

输出格式:

第一行一个数ans,表示最少的宠物数

第二行一个数p,代表给居民发的宠物数,接下来p个整数,表示获得宠物的居民

第三行一个数w,表示给守卫发的宠物数,接下来w个整数,表示获得宠物的守卫(编号为输入顺序)

题解

不难想到一个最小割模型,源点向居民连,守卫向汇点连,居民向覆盖的所有守卫连边,然后最小割。

然后倍增优化连边。

这题主要还得输出方案。

第一次遇到最小割要输出方案的。

方法是这样的,首先我们从源点开始\(dfs\)有流量的边,那么左部点一定是没有选的,\(dfs\)到的右部点一定是选了的,这时如果右部点有向左部点连的边,说明这个左部点也没选,那么继续从左部点开始点\(dfs\)

这样所有\(dfs\)到的左部点都没有被选,所有\(dfs\)到的右部点都被选了。

代码

#include
#define inf 2e9#define N 20009#define mm make_pair#define P pair
using namespace std;typedef long long ll;int p[20][N],id[20][N],now,tot=1,dep[N],n,m,rec[N];int head[N<<5],cur[N<<5],deep[N<<5];bool vis[N<<5];P re[N];queue
q;inline ll rd(){ ll x=0;char c=getchar();bool f=0; while(!isdigit(c)){if(c=='-')f=1;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} return f?-x:x;}vector
vec[N],ans1,ans2;vector
::iterator it;struct edge{ int n,to,l;}e[N<<6];inline void add(int u,int v,int l){ e[++tot].n=head[u];e[tot].to=v;head[u]=tot;e[tot].l=l; e[++tot].n=head[v];e[tot].to=u;head[v]=tot;e[tot].l=0;}inline bool bfs(int s,int t){ memset(deep,0,sizeof(deep)); memcpy(cur,head,sizeof(cur)); q.push(s);deep[s]=1; while(!q.empty()){ int u=q.front();q.pop(); for(int i=head[u];i;i=e[i].n){ int v=e[i].to; if(!deep[v]&&e[i].l){ deep[v]=deep[u]+1; q.push(v); } } } return deep[t];}int dfs(int u,int t,int l){ if(u==t||!l)return l; int f,flow=0; for(int &i=cur[u];i;i=e[i].n){ int v=e[i].to; if(deep[u]+1==deep[v]&&(f=dfs(v,t,min(l,e[i].l)))){ flow+=f;e[i].l-=f;e[i^1].l+=f;l-=f; if(!l)break; } } return flow;}void dfs(int u,int fa){ for(int i=1;(1<
<=dep[u];++i){ p[i][u]=p[i-1][p[i-1][u]]; id[i][u]=++now; add(id[i][u],id[i-1][u],inf); add(id[i][u],id[i-1][p[i-1][u]],inf); } for(vector
::iterator it=vec[u].begin();it!=vec[u].end();++it){ int v=*it; if(v==fa)continue; dep[v]=dep[u]+1; p[0][v]=u;id[0][v]=++now; dfs(v,u); }}inline int getlca(int u,int v){ if(dep[u]
=0;--i)if(dep[u]-(1<
=dep[v])u=p[i][u]; if(u==v)return u; for(int i=19;i>=0;--i)if(p[i][u]!=p[i][v]){ u=p[i][u];v=p[i][v]; } return p[0][u];}void ser(int u){ vis[u]=1; for(int i=head[u];i;i=e[i].n){ int v=e[i].to; if(!vis[v]&&e[i].l)ser(v); }}int main(){ n=rd();m=rd(); int x,y; for(int i=1;i
=0;--j){ if(p[j][x]&&dep[p[j][x]]>=dep[lca]){ add(now,id[j][x],inf); x=p[j][x]; } } for(int j=19;j>=0;--j){ if(p[j][y]&&dep[p[j][y]]>=dep[lca]){ add(now,id[j][y],inf); y=p[j][y]; } } } int ans=0; for(int i=2;i<=n;++i)add(id[0][i],now+1,1); while(bfs(0,now+1))ans+=dfs(0,now+1,inf); cout<
<
::iterator it=ans1.begin();it!=ans1.end();++it) printf("%d ",*it);puts(""); printf("%d ",ans2.size()); for(vector
::iterator it=ans2.begin();it!=ans2.end();++it) printf("%d ",*it); return 0;}

转载于:https://www.cnblogs.com/ZH-comld/p/10946503.html

你可能感兴趣的文章
Jackson异常情况处理
查看>>
Windows Server 2008R2 ADRMS 群集部署SOP
查看>>
squid+iptables实现透明代理
查看>>
phpMyWind本地伪静态设置方法_已迁移
查看>>
CentOS相关知识
查看>>
按钮特效
查看>>
Django 之 模板语言
查看>>
常用的敏捷测试工具
查看>>
JavaEE程序员必读图书大推
查看>>
CKEditor使用配置
查看>>
变频电源与变频器不同浅释
查看>>
利用HTML5将摄像头视频流转换成ascii码流,通过websocket实时传输给其它浏览器展示。...
查看>>
运维之道:16 张图片带你 1 小时学会 Ansible
查看>>
分享:IT管理员都喜欢用的Outlook超大附件系统
查看>>
objective-c设计模式之---单例
查看>>
golang读取json格式的天气预报
查看>>
每周一书《大数据搜索引擎原理分析及编程实现》分享!
查看>>
【网优谷】如何快速写出有吸引力的网站标题?
查看>>
Linux运维之lLinux文件系统及文件类型
查看>>
网站SEO优化过程中什么样的文章容易被秒收
查看>>