CF 786 E ALT
CF 786 E ALT
一个居民有两个选择:分配一只宠物,路上都有宠物
一个守卫有两种选择:分配一只宠物,不分配宠物
我们找一个原点,到每个居民都有一条边,表示是否给他宠物
从每个居民向他路上的守卫连边
守卫到汇点连边。
居民到守卫的边容量是 $ \infin $ ,所以现在达到的效果就是,要么一个居民被加边,要么一个居民连向守卫都被鸽。
一个居民连向了 $ O(n) $ 个点啊!
怎么优化?所以我们可以类似倍增 LCA 的方法,如果向一个点的第 $ j $ 个点连边,表示它向上跳 $ 2^k $ 个点那都连。最后边数是 $ m\log $ 。
最小割怎么输出方案呢?我们从 $ S $ 开始 dfs 一次,最终一条边两端的点一个没有被跑到过一个被跑到过的话,这个边就加入边集。
我觉得并不是非常好写。。(码力弱鸡)
#include "iostream"
#include "algorithm"
#include "cstring"
#include "cstdio"
#include "vector"
#include "queue"
#include "cmath"
using namespace std;
#define pii pair<int,int>
#define fi first
#define se second
#define mp make_pair
#define MAXN 50006
int cn = 2;
const int inf = 0x3f3f3f3f;
class maxFlow {
public:
typedef long long ll;
std::queue<int> q;
std::vector<int> head, cur, nxt, to, dep;
std::vector<ll> cap;
maxFlow(int _n = 0) { init(_n); }
void init(int _n) {
head.clear();
head.resize(_n + 1, 0);
nxt.resize(2);
to.resize(2);
cap.resize(2);
}
void init() { init(head.size() - 1); }
int add(int u, int v, ll w) {
nxt.push_back(head[u]);
int x = ( head[u] = to.size() );
to.push_back(v);
cap.push_back(w);
return x;
}
int Add(int u, int v, ll w) {
// printf("%d %d %d\n",u,v,w);
add(u, v, w);
return add(v, u, 0);
}
void del(int x) { cap[x << 1] = cap[x << 1 | 1] = 0; }
bool bfs(int s, int t, int delta) {
dep.clear();
dep.resize(head.size(), -1);
dep[s] = 0;
q.push(s);
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = head[u]; i; i = nxt[i]) {
int v = to[i];
ll w = cap[i];
if (w >= delta && dep[v] == -1) {
dep[v] = dep[u] + 1;
q.push(v);
}
}
}
return ~dep[t];
}
ll dfs(int u, ll flow, int t, int delta) {
if (dep[u] == dep[t])
return u == t ? flow : 0;
ll out = 0;
for (int& i = cur[u]; i; i = nxt[i]) {
int v = to[i];
ll w = cap[i];
if (w >= delta && dep[v] == dep[u] + 1) {
ll f = dfs(v, std::min(w, flow - out), t, delta);
cap[i] -= f;
cap[i ^ 1] += f;
out += f;
if (out == flow)
return out;
}
}
return out;
}
ll maxflow(int s, int t) {
ll out = 0;
ll maxcap = *max_element(cap.begin(), cap.end());
for (ll delta = 1ll << int(log2(maxcap) + 1e-12); delta; delta >>= 1) {
while (bfs(s, t, delta)) {
cur = head;
out += dfs(s, 0x7fffffffffffffffll, t, delta);
}
}
return out;
}
ll getflow(int x) const { return cap[x << 1 | 1]; }
int vis[3000000];
void work( int u ) {
vis[u] = 1;
for( int i = head[u] ; i ; i = nxt[i] ) if( cap[i] ) {
int v = to[i];
if( !vis[v] ) work( v );
}
}
} F ;
int n , m;
vector<int> G[MAXN];
int g[MAXN][16] , p[MAXN][16] , dep[MAXN];
int T[MAXN] , S[MAXN] , tt[MAXN] , bacs[3000000] , bact[3000000];
void dfs( int u , int fa ) {
for( int v : G[u] ) if( v != fa ) {
dep[v] = dep[u] + 1;
g[v][0] = u , p[v][0] = ++ cn;
T[v] = F.Add( p[v][0] , 2 , 1 );
for( int k = 1 ; k < 16 ; ++ k )
if( g[g[v][k-1]][k-1] ) {
g[v][k] = g[g[v][k-1]][k-1];
p[v][k] = ++ cn;
F.Add( p[v][k] , p[v][k - 1] , inf );
F.Add( p[v][k] , p[g[v][k-1]][k-1] , inf );
} else break;
dfs( v , u );
}
}
void link( int i , int u , int v ) { // id -> u~v
if( dep[u] < dep[v] ) swap( u , v );
for( int k = 15 ; k >= 0 ; -- k )
if( dep[g[u][k]] >= dep[v] )
F.Add( i , p[u][k] , inf ) , u = g[u][k];
if( u == v ) return;
for( int k = 15 ; k >= 0 ; -- k )
if( g[u][k] != g[v][k] )
F.Add( i , p[u][k] , inf ) , F.Add( i , p[v][k] , inf ) , u = g[u][k] , v = g[v][k];
F.Add( i , p[u][0] , inf ) , F.Add( i , p[v][0] , inf );
}
vector<int> s , t;
pii E[MAXN];
int main() {
cin >> n >> m;
F.init( 3000000 );
for( int i = 1 , u , v ; i < n ; ++ i ) {
scanf("%d%d",&u,&v);
G[u].push_back( v ) , G[v].push_back( u );
E[i] = mp( u , v );
}
dep[1] = 1 , dfs( 1 , 1 );
for( int i = 1 ; i < n ; ++ i )
if( g[E[i].fi][0] == E[i].se ) tt[i] = T[E[i].fi];
else tt[i] = T[E[i].se];
for( int i = 1 , u , v ; i <= m ; ++ i ) {
scanf("%d%d",&u,&v);
S[i] = F.Add( 1 , ++ cn , 1 );
link( cn , u , v );
}
cout << F.maxflow( 1 , 2 ) << endl;
for( int i = 1 ; i <= m ; ++ i ) bacs[S[i]] = i;
for( int i = 1 ; i < n ; ++ i ) bact[tt[i]] = i;
F.work( 1 );
for( int i = F.head[1] ; i ; i = F.nxt[i] ) if( !F.vis[F.to[i]] )
s.push_back( bacs[i ^ 1] );
// F.work( 2 );
for( int i = F.head[2] ; i ; i = F.nxt[i] ) if( F.vis[2] ^ F.vis[F.to[i]] )
t.push_back( bact[i] );
cout << s.size() << ' '; for( auto i : s ) printf("%d ",i); puts("");
cout << t.size() << ' '; for( auto i : t ) printf("%d ",i); puts("");
}
CF 786 E ALT的更多相关文章
- cf 786 B 线段树优化建图
cf 786 B 链接 CF 思路 n个点,3种建边方式,规模\(O(n^2)\) 线段树优化建图 注意 读入的数据好坑啊,说好的v,u变成了u,v. 两棵树,一棵出,一棵入.线段树的作用只不过是按照 ...
- puppet介绍与安装
puppet是什么puppet是一种基于ruby语言开发的Lnux.Unix.windows平台的集中配置管理系统.它使用自有的puppet描述语言,可管理配置文件file.用户user.cron任务 ...
- [No000093]按住Alt 再按数字键敲出任意汉字和字符!
1.在notepad里,(中文系统下) 按住Alt 然后按52946最后放开Alt 按住Alt 然后按45230最后放开Alt 按住Alt 然后按50403最后放开Alt 你会看到"我爱你& ...
- Codeforces 786E. ALT 最小割+倍增
E. ALT http://codeforces.com/problemset/problem/786/E 题意: 给出一棵 n 个节点的树与 m 个工人.每个工人有一条上下班路线(简单路径),一个工 ...
- 【机器学习算法-python实现】协同过滤(cf)的三种方法实现
(转载请注明出处:http://blog.csdn.net/buptgshengod) 1.背景 协同过滤(collaborative filtering)是推荐系统经常使用的一种方法.c ...
- CF 372B Counting Rectangles is Fun [dp+数据维护]
题意,给出一个n行m列的矩阵 里面元素是0或者1 给出q个询问 a,b,c,d 求(a,b)到(c,d)有多少个由0组成的矩形 我们定义 watermark/2/text/aHR0cDovL2Jsb2 ...
- ORA-00494: enqueue [CF] held for too long (more than 900 seconds) by 'inst 1, osid 5166'
凌晨收到同事电话,反馈应用程序访问Oracle数据库时报错,当时现场现象确认: 1. 应用程序访问不了数据库,使用SQL Developer测试发现访问不了数据库.报ORA-12570 TNS:pac ...
- [No00008B]远程桌面发送“Ctrl+Alt+Delete”组合键调用任务管理器
向远程桌面发送"Ctrl+Alt+Delete"组合键的两种方法 1.在本地按下Ctrl+Alt+End,可以成功发送"Ctrl+Alt+Delete"组合键! ...
- 平常看到的Alt+xx 快捷键用法
1. 先按Alt, 哪一个菜单对应的字符是有划线的. 2. 输入对应的字符打开相应的菜单, 3 再输入相应的字符打开子菜单
随机推荐
- 求求你了,用Docker吧
这是一个开始使用 Docker 的 Tutorial 大无语事件发生!大数据课实验课要用到Hadoop,实验指导是在一个Ubuntu虚机上通过安装包安装Hadoop并运行一个词频统计程序,整个实验就是 ...
- Java:ArrayList类小记
Java:ArrayList类小记 对 Java 中的 ArrayList类,做一个微不足道的小小小小记 概述 java.util.ArrayList 是大小可变的数组的实现,存储在内的数据称为元素. ...
- 深入理解xLua基于IL代码注入的热更新原理
目前大部分手游都会采用热更新来解决应用商店审核周期长,无法满足快节奏迭代的问题.另外热更新能够有效降低版本升级所需的资源大小,节省玩家的时间和流量,这也使其成为移动游戏的主流更新方式之一. 热更新可以 ...
- Python中的括号()、[]、{}
长时间不用容易混淆,仅记! 在Python语言中最常见的括号有三种,分别是:小括号().中括号[].花括号{} . Python中的小括号(): 代表tuple元祖数据类型,元祖是一种不可变序列.大多 ...
- Redis的浅入门
Redis的浅入门 # 缓存的思想 问题提出:我们的用户数量上亿,如果登录,访问数据库user特别耗时,该怎么办?--提出缓存 方法:怎样从缓存在获取数据? *有数据: 直接返回 *无数据: (1)从 ...
- (类)Program1.1
1 class MyClass: 2 3 i = 12345 4 5 def __init__(self): 6 self.data = "WOOWOWOWO" 7 8 def f ...
- 整数中1出现的次数 牛客网 剑指Offer
整数中1出现的次数 牛客网 剑指Offer 题目描述 求出113的整数中1出现的次数,并算出1001300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1.10.11.12.13因此 ...
- 原串反转 牛客网 程序员面试金典 C++ Python
原串反转 牛客网 程序员面试金典 C++ Python 题目描述 请实现一个算法,在不使用额外数据结构和储存空间的情况下,翻转一个给定的字符串(可以使用单个过程变量). 给定一个string iniS ...
- 近期业务大量突增微服务性能优化总结-3.针对 x86 云环境改进异步日志等待策略
最近,业务增长的很迅猛,对于我们后台这块也是一个不小的挑战,这次遇到的核心业务接口的性能瓶颈,并不是单独的一个问题导致的,而是几个问题揉在一起:我们解决一个之后,发上线,之后发现还有另一个的性能瓶颈问 ...
- Linux常用命令和快捷键整理:(2)常用快捷键
前言: Linux常用快捷键和基本命令整理,先上思维导图: linux常用命令请见:https://www.cnblogs.com/yinzuopu/p/15516499.html 基本快捷键的使用 ...