如果把“我全都要”看作是我全不要的话,就可以用最小割解决啦

源点S,汇点T

我们试图让每个市民作为一个等待被割断的路径

把狗狗给市民:建边(S,i,1),其中i是市民

把狗狗给守卫:建边(j,T,1),其中j是守卫(也就是边)

市民要在路上所有边看到狗:建边(i,j,1),其中i是市民,j是i经过的边

(众所周知,(!A)&(!B)==!(A|B),所以要把两种选择串起来)

然而这样边数太多了,考虑倍增来优化建边

...反正就是倍增优化建边,流量给正无穷

最大流=最小割,跑个dinic就行了(要加当前弧优化不然会T)

然后考虑输出方案。一个边如果被割断了,那么它的残余容量就是0

所以我们来从Sdfs一下,如果能搜到某个人,说明他没有狗;如果能搜到某条边,又因为S和T不连通,说明这条边到T要被割断,说明它有狗

各种各样的数组开大一点又不会怀孕

 #include<bits/stdc++.h>
#define pa pair<int,int>
#define CLR(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn=2e4+,inf=0x3f3f3f3f; inline ll rd(){
ll x=;char c=getchar();int neg=;
while(c<''||c>''){if(c=='-') neg=-;c=getchar();}
while(c>=''&&c<='') x=x*+c-'',c=getchar();
return x*neg;
} struct Edge{
int b,l,ne;
}ek[maxn*];
int N,M,ekh[maxn*],kct=;
int egh[maxn],eg[maxn*][],ect=;
int dep[maxn*],fa[maxn][],id[maxn][],pct=;
int S=,T=,P[maxn];
int A[maxn],cur[maxn*];
bool flag[maxn*],B[maxn];
queue<int> q; inline void adeg(int a,int b){
eg[++ect][]=b;eg[ect][]=egh[a];egh[a]=ect;
}
inline void adek(int a,int b,int c){
// printf("!%d %d %d\n",a,b,c);
ek[++kct].b=b,ek[kct].l=c,ek[kct].ne=ekh[a],ekh[a]=kct;
ek[++kct].b=a,ek[kct].l=,ek[kct].ne=ekh[b],ekh[b]=kct;
} void dfs(int x){
for(int i=;fa[x][i]&&fa[fa[x][i]][i];i++){
fa[x][i+]=fa[fa[x][i]][i];
id[x][i+]=++pct;
adek(id[x][i+],id[x][i],inf);
adek(id[x][i+],id[fa[x][i]][i],inf);
}
for(int i=egh[x];i;i=eg[i][]){
int b=eg[i][];
if(b==fa[x][]) continue;
fa[b][]=x;dep[b]=dep[x]+;
id[b][]=++pct;adek(id[b][],T,);
// printf("~%d %d\n",b,id[b][0]);
dfs(b);
}
} void buildlca(int x,int y,int p){
if(dep[x]<dep[y]) swap(x,y);
for(int i=log2(dep[x]-dep[y]);i>=&&dep[x]!=dep[y];i--){
if(dep[fa[x][i]]>=dep[y]){
adek(p,id[x][i],);
x=fa[x][i];
}
}
if(x==y) return;
for(int i=log2(dep[x]);i>=;i--){
if(fa[x][i]!=fa[y][i]){
adek(p,id[x][i],);adek(p,id[y][i],);
x=fa[x][i],y=fa[y][i];
}
}
adek(p,id[x][],);adek(p,id[y][],); } bool bfs(){
CLR(dep,);CLR(cur,-);
dep[S]=;q.push(S);
while(!q.empty()){
int p=q.front();q.pop();
// printf("!@#%d %d\n",p,dep[p]);
for(int i=ekh[p];i;i=ek[i].ne){
int b=ek[i].b;
if(dep[b]||!ek[i].l) continue;
dep[b]=dep[p]+;
q.push(b);
}
}
return dep[T];
} int dinic(int x,int y){
if(x==T) return y;
int tmp=y;
if(cur[x]==-) cur[x]=ekh[x];
for(int &i=cur[x];i;i=ek[i].ne){
// printf("%d %d\n",i,cur[x]);
int b=ek[i].b;
if(dep[b]!=dep[x]+||!ek[i].l) continue;
int re=dinic(b,min(ek[i].l,tmp));
ek[i].l-=re,ek[i^].l+=re;
tmp-=re;if(!tmp) break;
}return y-tmp;
} void getans(int x){
flag[x]=;
for(int i=ekh[x];i;i=ek[i].ne){
int b=ek[i].b;
if(!ek[i].l) continue;
if(!flag[b]) getans(b);
}
} int main(){
// freopen("768E.in","r",stdin);
int i,j,k;
N=rd(),M=rd();
for(i=;i<N;i++){
int a=rd(),b=rd();
adeg(a,b);adeg(b,a);
}
for(i=;i<=M;i++) P[i]=++pct;
dep[]=;dfs();
for(i=;i<=M;i++){
int a=rd(),b=rd();
adek(S,P[i],);
buildlca(a,b,P[i]);
}
int ans=,a=,b=;
while(bfs()) ans+=dinic(S,inf);
getans(S);
for(i=;i<=M+;i++)
if(!flag[i]) A[++a]=i-;
for(i=;i<=N;i++)
if(flag[id[i][]]) B[i]=,b++;
printf("%d\n%d ",ans,a);
for(i=;i<=a;i++)
printf("%d ",A[i]);
printf("\n%d ",b);
for(i=;i<N;i++){
int x=eg[i<<][],y=eg[i<<|][];
if(fa[x][]!=y) swap(x,y);
// printf("!%d %d!\n",x,y);
if(B[x]) printf("%d ",i);
} return ;
}

cf786E ALT (最小割+倍增优化建图)的更多相关文章

  1. [bzoj3218] a+b problem [最小割+数据结构优化建图]

    题面 传送门 思路 最小割 我们首先忽略掉那个奇♂怪的限制,就有一个比较显然的最小割模型: 建立源点$S$和汇点$T$ 对于每个元素$i$建立一个点$i$,连边$<S,i,w[i]>$和$ ...

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

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

  3. [十二省联考2019]字符串问题——后缀自动机+parent树优化建图+拓扑序DP+倍增

    题目链接: [十二省联考2019]字符串问题 首先考虑最暴力的做法就是对于每个$B$串存一下它是哪些$A$串的前缀,然后按每组支配关系连边,做一遍拓扑序DP即可. 但即使忽略判断前缀的时间,光是连边的 ...

  4. 一个神秘的oj2587 你猜是不是dp(线段树优化建图)

    哇 这难道不是happiness的翻版题嘛? 从\(S\)向一个点连染成白色的收益 从这个点向\(T\)连染成黑色的收益 对于额外的收益,建一个辅助点,跟区间内的每个点连\(inf\),然后向S/T, ...

  5. [SDOI2017]天才黑客[最短路、前缀优化建图]

    题意 一个 \(n\) 点 \(m\) 边的有向图,还有一棵 \(k\) 个节点的 trie ,每条边上有一个字符串,可以用 trie 的根到某个节点的路径来表示.每经过一条边,当前携带的字符串就会变 ...

  6. BZOJ_4276_[ONTAK2015]Bajtman i Okrągły Robin_线段树优化建图+最大费用最大流

    BZOJ_4276_[ONTAK2015]Bajtman i Okrągły Robin_线段树优化建图+最大费用最大流 Description 有n个强盗,其中第i个强盗会在[a[i],a[i]+1 ...

  7. Nowcoder Hash Function ( 拓扑排序 && 线段树优化建图 )

    题目链接 题意 : 给出一个哈希表.其避免冲突的方法是线性探测再散列.现在问你给出的哈希表是否合法.如果合法则输出所有元素插入的顺序.如果有多解则输出字典序最小的那一个.如果不合法则输出 -1 分析 ...

  8. bzoj5017 [Snoi2017]炸弹 (线段树优化建图+)tarjan 缩点+拓扑排序

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5017 题解 这个题目方法挺多的. 线段树优化建图 线段树优化建图的做法应该挺显然的,一个炸弹能 ...

  9. 洛谷 P3783 - [SDOI2017]天才黑客(前后缀优化建图)

    题面传送门 神仙题一道. 首先注意到这里的贡献涉及到边的顺序,并且只与相邻的边是什么有关,因此不难想到一个做法--边转点,点转边,具体来说对于每条边 \(e\),我们将其拆成两个点 \(in_e,ou ...

随机推荐

  1. 浅淡volatile原理

    Volatile是轻量级的synchronized,它在多处理器开发中保证了共享变量的“可见性” Volatile的官方定义 Java语言规范第三版中对volatile的定义如下: java编程语言允 ...

  2. EZ 2018 05 20 NOIP2018 模拟赛(十五)

    这次的比赛充满着玄学的气息,玄学链接 首先讲一下为什么没有第十四场 其实今天早上9点时看到题目就叫了:原题! 没错,整套试卷都做过,我还写了题解 然后老叶就说换一套,但如果仅仅是这样就没什么 但等13 ...

  3. 个人博客地址: furur.xyz

    趁着Hexo的热度,最近就买了域名,在GitHub Pages上搭了个人博客.也不是说博客园不好吧,毕竟在博客园三年多,也学到了不少东西,唯一要吐槽的,估计也就是后台管理不方便,markdown无即时 ...

  4. 5分钟入门自动化测试——你应该学会的Postman用法(2)

    前言 之前的一篇文章<你应该学会的Postman用法>,主要介绍了postman的一些高级的用法,便于日常开发和调试使用,本文的基础是对postman的基本使用以及一些高级用法有一定的了解 ...

  5. C语言基础复习:字符,字符数组,字符串,字符指针

    1. 概述2. 字符2.1 字符定义和大小2.2 字符的输入和输出2.3 字符的计算3. 字符数组3.1 字符数组的定义和大小3.2 字符数组的输入和输出3.3 字符数组的计算4. 字符串4.1 字符 ...

  6. linux内实践核分析模块

  7. 基于UML的需求分析和系统设计

    小序: 从学生时代就接触到UML,几年的工作中也没少使用,各种图形的概念.图形的元素和属性,以及图形的画法都不能说不熟悉.但是怎样在实际中有效地使用UML使之发挥应有的作用,怎样捕捉用户心中的需求并转 ...

  8. PHP和JavaScript将字符串转换为数字string2int

    在看廖雪峰的JavaScript教程时,里面有一个题就是利用reduce()将string转换为int,我看评论中贴出的方法,当时觉得挺意外了,以为他只用了一行代码,即下面这行代码 var str=& ...

  9. ASP.NET MVC4学习笔记

    一.MVC简介

  10. Oracle Gateways 方式创建dblink 连接 SQLSERVER数据库

    1. 安装多次 发现在同一个机器上面总出问题,所以建议找一个没有安装oracle的机器上面进行安装gateways 2. 下载oracle gateways 并且解压缩, 下载地址详情见官网. 下载的 ...