方案二选一,显然是最小割,朴素的想法就是一排人点一排边点,分别向st连流量1的边,然后人点向路径上的边点连流量inf的边跑最大流

但是路径可能很长,这样边数就爆了,所以考虑倍增,然后倍增后大区间向小区间连,这样路径只要连向log个区间就行了,然后跑最大流

输出方案是在残量网络上从s点沿着没满流的边bfs,因为满流的边一定在最小割里,所以没有访问到的人点和访问到的边点就是能得到宠物的

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
const int N=400005;
int n,m,h[N],cnt,p[N],le[N],si[N],hs[N],fa[N],de[N],fr[N],s,t,id[N][16],tot,f[N][16];
vector<int>a1,a2;
struct qwe
{
int ne,to,va;
}e[N*20];
int read()
{
int r=0,f=1;
char p=getchar();
while(p>'9'||p<'0')
{
if(p=='-')
f=-1;
p=getchar();
}
while(p>='0'&&p<='9')
{
r=r*10+p-48;
p=getchar();
}
return r*f;
}
void ade(int u,int v,int w)
{
cnt++;
e[cnt].ne=h[u];
e[cnt].to=v;
e[cnt].va=w;
h[u]=cnt;
}
void dfs1(int u,int fat)
{
fa[u]=f[u][0]=fat;
si[u]=1;
de[u]=de[fat]+1;
for(int i=h[u];i;i=e[i].ne)
if(e[i].to!=fat)
{
p[e[i].to]=e[i].va;
dfs1(e[i].to,u);
si[u]+=si[e[i].to];
if(si[e[i].to]>si[hs[u]])
hs[u]=e[i].to;
}
}
void dfs2(int u,int top)
{
fr[u]=top;
if(!hs[u])
return;
dfs2(hs[u],top);
for(int i=h[u];i;i=e[i].ne)
if(e[i].to!=fa[u]&&e[i].to!=hs[u])
dfs2(e[i].to,e[i].to);
}
int lca(int u,int v)
{
for(;fr[u]!=fr[v];de[fr[u]]>de[fr[v]]?u=fa[fr[u]]:v=fa[fr[v]]);
return de[u]<de[v]?u:v;
}
void add(int u,int v,int w)
{
cnt++;
e[cnt].ne=h[u];
e[cnt].to=v;
e[cnt].va=w;
h[u]=cnt;
}
void ins(int u,int v,int w)
{//cerr<<u<<" "<<v<<" "<<w<<endl;
add(u,v,w);
add(v,u,0);
}
bool bfs()
{
memset(le,0,sizeof(le));
queue<int>q;
q.push(s);
le[s]=1;
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=h[u];i;i=e[i].ne)
if(e[i].va&&!le[e[i].to])
{
le[e[i].to]=le[u]+1;
q.push(e[i].to);
}
}
return le[t];
}
int dfs(int u,int f)
{
if(u==t||!f)
return f;
int us=0;
for(int i=h[u];i&&us<f;i=e[i].ne)
if(e[i].va&&le[e[i].to]==le[u]+1)
{
int t=dfs(e[i].to,min(e[i].va,f-us));
e[i].va-=t;
e[i^1].va+=t;
us+=t;
}
if(!us)
le[u]=0;
return us;
}
int dinic()
{
int r=0;
while(bfs())
r+=dfs(s,1e9);
return r;
}
void wk(int x,int lc,int i)
{
int z=fa[fr[x]];
while(x!=z&&de[x]>de[lc])
ins(i,x+m,1e9),x=fa[x];//,cerr<<1<<" "<<x<<endl;
while(de[fr[x]]>de[lc])
ins(i,fr[x]+n+m,1e9),x=fa[fr[x]];//,cerr<<2<<" "<<x<<endl;
while(de[x]>de[lc])
ins(i,x+m,1e9),x=fa[x];
}
int main()
{
n=read(),tot=m=read();
for(int i=1;i<n;i++)
{
int x=read(),y=read();
ade(x,y,i),ade(y,x,i);
}
dfs1(1,0);
dfs2(1,1);
memset(h,0,sizeof(h));
cnt=1;
for(int i=1;i<=n;i++)
id[i][0]=++tot;
for(int j=1;j<=15;j++)
for(int i=1;i<=n;i++)
{
f[i][j]=f[f[i][j-1]][j-1];
if(i!=1)
id[i][j]=++tot;
if(id[i][j-1])
ins(id[i][j],id[i][j-1],1e9);
if(id[f[i][j-1]][j-1])
ins(id[i][j],id[f[i][j-1]][j-1],1e9);
}
s=0,t=tot+1;
for(int i=2;i<=n;i++)
ins(id[i][0],t,1);
for(int i=1;i<=m;i++)
{
ins(s,i,1);
int x=read(),y=read(),lc=lca(x,y);
if(de[x]>de[y])
swap(x,y);
for(int d=de[y]-de[x],k=15,t=(1<<15);d;k--,t/=2)
if(d>=t)
{
d-=t;
ins(i,id[y][k],1e9);
y=f[y][k];
}
if(x!=y)
{
for(int k=15;k>=0;k--)
if(f[x][k]!=f[y][k])
{
ins(i,id[x][k],1e9);
ins(i,id[y][k],1e9);
x=f[x][k],y=f[y][k];
}
ins(i,id[x][0],1e9);
ins(i,id[y][0],1e9);
}
}
printf("%d\n",dinic());
memset(le,0,sizeof(le));
queue<int>q;
q.push(s);
le[s]=1;
while(!q.empty())
{
int u=q.front();//cerr<<u<<endl;
q.pop();
for(int i=h[u];i;i=e[i].ne)
if(!le[e[i].to]&&e[i].va>0)
{
le[e[i].to]=1;
q.push(e[i].to);
}
}
for(int i=1;i<=m;i++)
if(!le[i])
a1.push_back(i);
for(int i=2;i<=n;i++)
if(le[i+m])
a2.push_back(p[i]);
printf("%d ",a1.size());
for(int i=0;i<a1.size();i++)
printf("%d ",a1[i]);
puts("");
printf("%d ",a2.size());
for(int i=0;i<a2.size();i++)
printf("%d ",a2[i]);
return 0;
}

codeforces786E ALT【倍增+最小割】的更多相关文章

  1. Codeforces 786E. ALT 最小割+倍增

    E. ALT http://codeforces.com/problemset/problem/786/E 题意: 给出一棵 n 个节点的树与 m 个工人.每个工人有一条上下班路线(简单路径),一个工 ...

  2. cf786E ALT (最小割+倍增优化建图)

    如果把“我全都要”看作是我全不要的话,就可以用最小割解决啦 源点S,汇点T 我们试图让每个市民作为一个等待被割断的路径 把狗狗给市民:建边(S,i,1),其中i是市民 把狗狗给守卫:建边(j,T,1) ...

  3. (2016北京集训十三)【xsy1532】网络战争 - 最小割树+树上倍增+KD树

    题解: 好题!! 这题似乎能上我代码长度记录的前五? 调试时间长度应该也能上前五QAQ 首先题目要求的明显就是最小割,当然在整个森林上求Q次最小割肯定是会GG的,所以我们需要一个能快速求最小割的算法— ...

  4. BZOJ2229[Zjoi2011]最小割——最小割树

    题目描述 小白在图论课上学到了一个新的概念——最小割,下课后小白在笔记本上写下了如下这段话: “对于一个图,某个对图中结点的划分将图中所有结点分成两个部分,如果结点s,t不在同一个部分中,则称这个划分 ...

  5. [模板]最小割树(Gomory-Hu Tree)(luogu4897)

    给定一个\(n\)个点\(m\)条边的无向连通图,多次询问两点之间的最小割 两点间的最小割是这样定义的:原图的每条边有一个割断它的代价,你需要用最小的代价使得这两个点不连通 Input 第一行两个数\ ...

  6. 网络战争 [KD-Tree+最小割树]

    题面 思路 首先吐槽一下: 这题是什么东西啊??出题人啊,故意拼题很有意思吗??还拼两个这么毒瘤的东西???? 10K代码了解一下???? 然后是正经东西 首先,本题可以理解为这样: 给定$n$个块, ...

  7. 最小割树(Gomory-Hu Tree)求无向图最小割详解 附 BZOJ2229,BZOJ4519题解

    最小割树(Gomory-Hu Tree) 前置知识 Gomory-Hu Tree是用来解决无向图最小割的问题的,所以我们需要了解无向图最小割的定义 和有向图类似,无向图上两点(x,y)的割定义为一个边 ...

  8. [学习笔记]最小割树(Gomory-Hu Tree)

    最小割树(\(\mathcal{Gomory-Hu Tree}\))简明指南 对于单源最短路径,我们有\(SPFA\)和\(Dijkstra\),对于多源最短路径,我们有\(Floyd\):对于两点间 ...

  9. BZOJ 1391: [Ceoi2008]order [最小割]

    1391: [Ceoi2008]order Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1509  Solved: 460[Submit][Statu ...

随机推荐

  1. CUDA:零拷贝主机内存

    The easy way to achieve copy/compute overlap!1.Enable Host Mapping* Runtime: cudaSetDeviceFlags() wi ...

  2. Antler 工具使用(.g 转.java / .cs)

    1. JAVA环境 2. Antler 工具包: antlr-3.5.1-complete-no-st3.jar 路径加入classpath 3. cmd命令行: java org.antlr.Too ...

  3. struts2 codebehind + actionPackages 实现Action零配置

    1.jar包:struts2-codebehind-plugin-2.2.1.1.jar 2.struts.xml:<!-- codebehind中查找action的返回结果资源时的默认文件夹 ...

  4. C++ 构造函数+析构函数

    3-2 构造函数的调用 Time Limit: 1000MS Memory limit: 65536K 题目描述 通过本题目的练习可以掌握构造函数和析构函数的调用: 创建类A:类中仅包含构造函数和析构 ...

  5. spring 路径配置通配符是如何实现的

    在spring的配置文件中.经常看见类似这样的配置路径: classpath:/com/module/**/*sql.xml 系统会根据配置路径自动加载符合路径规则的xml文件. Spring还提供了 ...

  6. struts2的结果类型

    1.从struts-default.xml入手,得到结果类型列表以及对应的处理类: <result-types> <!-- 转发到action --> <result-t ...

  7. jsp日期插件My97DatePicker 强大的日期控件 使用方便简单(转)

    本文属转载(希望对编程爱好者有所帮助)详情请访问官方网站 http://www.my97.net/dp/index.asp 一. 简介 1. 简介 目前的版本是:4.7 2. 注意事项 My97Dat ...

  8. L92

    The Difference between Honesty and Cheating We sign our names to various documents all the time. Som ...

  9. listen 68 Theoretical Physicist Stephen Hawking Dies at 76

    World-renowned British physicist Stephen Hawking, who sought to understand a range of cosmic topics ...

  10. 为什么修改头文件make不重新编译

    make是根据依赖文件的时间戳来决定要不要重新编译的.在: object: deplist # actions 中,可以把头文件加进deplist,这样修改头文件后,make就会重新编译了. 单纯地修 ...