CF 786 E ALT

一个居民有两个选择:分配一只宠物,路上都有宠物

一个守卫有两种选择:分配一只宠物,不分配宠物

我们找一个原点,到每个居民都有一条边,表示是否给他宠物

从每个居民向他路上的守卫连边

守卫到汇点连边。

居民到守卫的边容量是 $ \infin $ ,所以现在达到的效果就是,要么一个居民被加边,要么一个居民连向守卫都被鸽。

一个居民连向了 $ O(n) $ 个点啊!

怎么优化?所以我们可以类似倍增 LCA 的方法,如果向一个点的第 $ j $ 个点连边,表示它向上跳 $ 2^k $ 个点那都连。最后边数是 $ m\log $ 。

最小割怎么输出方案呢?我们从 $ S $ 开始 dfs 一次,最终一条边两端的点一个没有被跑到过一个被跑到过的话,这个边就加入边集。

我觉得并不是非常好写。。(码力弱鸡)

  1. #include "iostream"
  2. #include "algorithm"
  3. #include "cstring"
  4. #include "cstdio"
  5. #include "vector"
  6. #include "queue"
  7. #include "cmath"
  8. using namespace std;
  9. #define pii pair<int,int>
  10. #define fi first
  11. #define se second
  12. #define mp make_pair
  13. #define MAXN 50006
  14. int cn = 2;
  15. const int inf = 0x3f3f3f3f;
  16. class maxFlow {
  17. public:
  18. typedef long long ll;
  19. std::queue<int> q;
  20. std::vector<int> head, cur, nxt, to, dep;
  21. std::vector<ll> cap;
  22. maxFlow(int _n = 0) { init(_n); }
  23. void init(int _n) {
  24. head.clear();
  25. head.resize(_n + 1, 0);
  26. nxt.resize(2);
  27. to.resize(2);
  28. cap.resize(2);
  29. }
  30. void init() { init(head.size() - 1); }
  31. int add(int u, int v, ll w) {
  32. nxt.push_back(head[u]);
  33. int x = ( head[u] = to.size() );
  34. to.push_back(v);
  35. cap.push_back(w);
  36. return x;
  37. }
  38. int Add(int u, int v, ll w) {
  39. // printf("%d %d %d\n",u,v,w);
  40. add(u, v, w);
  41. return add(v, u, 0);
  42. }
  43. void del(int x) { cap[x << 1] = cap[x << 1 | 1] = 0; }
  44. bool bfs(int s, int t, int delta) {
  45. dep.clear();
  46. dep.resize(head.size(), -1);
  47. dep[s] = 0;
  48. q.push(s);
  49. while (!q.empty()) {
  50. int u = q.front();
  51. q.pop();
  52. for (int i = head[u]; i; i = nxt[i]) {
  53. int v = to[i];
  54. ll w = cap[i];
  55. if (w >= delta && dep[v] == -1) {
  56. dep[v] = dep[u] + 1;
  57. q.push(v);
  58. }
  59. }
  60. }
  61. return ~dep[t];
  62. }
  63. ll dfs(int u, ll flow, int t, int delta) {
  64. if (dep[u] == dep[t])
  65. return u == t ? flow : 0;
  66. ll out = 0;
  67. for (int& i = cur[u]; i; i = nxt[i]) {
  68. int v = to[i];
  69. ll w = cap[i];
  70. if (w >= delta && dep[v] == dep[u] + 1) {
  71. ll f = dfs(v, std::min(w, flow - out), t, delta);
  72. cap[i] -= f;
  73. cap[i ^ 1] += f;
  74. out += f;
  75. if (out == flow)
  76. return out;
  77. }
  78. }
  79. return out;
  80. }
  81. ll maxflow(int s, int t) {
  82. ll out = 0;
  83. ll maxcap = *max_element(cap.begin(), cap.end());
  84. for (ll delta = 1ll << int(log2(maxcap) + 1e-12); delta; delta >>= 1) {
  85. while (bfs(s, t, delta)) {
  86. cur = head;
  87. out += dfs(s, 0x7fffffffffffffffll, t, delta);
  88. }
  89. }
  90. return out;
  91. }
  92. ll getflow(int x) const { return cap[x << 1 | 1]; }
  93. int vis[3000000];
  94. void work( int u ) {
  95. vis[u] = 1;
  96. for( int i = head[u] ; i ; i = nxt[i] ) if( cap[i] ) {
  97. int v = to[i];
  98. if( !vis[v] ) work( v );
  99. }
  100. }
  101. } F ;
  102. int n , m;
  103. vector<int> G[MAXN];
  104. int g[MAXN][16] , p[MAXN][16] , dep[MAXN];
  105. int T[MAXN] , S[MAXN] , tt[MAXN] , bacs[3000000] , bact[3000000];
  106. void dfs( int u , int fa ) {
  107. for( int v : G[u] ) if( v != fa ) {
  108. dep[v] = dep[u] + 1;
  109. g[v][0] = u , p[v][0] = ++ cn;
  110. T[v] = F.Add( p[v][0] , 2 , 1 );
  111. for( int k = 1 ; k < 16 ; ++ k )
  112. if( g[g[v][k-1]][k-1] ) {
  113. g[v][k] = g[g[v][k-1]][k-1];
  114. p[v][k] = ++ cn;
  115. F.Add( p[v][k] , p[v][k - 1] , inf );
  116. F.Add( p[v][k] , p[g[v][k-1]][k-1] , inf );
  117. } else break;
  118. dfs( v , u );
  119. }
  120. }
  121. void link( int i , int u , int v ) { // id -> u~v
  122. if( dep[u] < dep[v] ) swap( u , v );
  123. for( int k = 15 ; k >= 0 ; -- k )
  124. if( dep[g[u][k]] >= dep[v] )
  125. F.Add( i , p[u][k] , inf ) , u = g[u][k];
  126. if( u == v ) return;
  127. for( int k = 15 ; k >= 0 ; -- k )
  128. if( g[u][k] != g[v][k] )
  129. F.Add( i , p[u][k] , inf ) , F.Add( i , p[v][k] , inf ) , u = g[u][k] , v = g[v][k];
  130. F.Add( i , p[u][0] , inf ) , F.Add( i , p[v][0] , inf );
  131. }
  132. vector<int> s , t;
  133. pii E[MAXN];
  134. int main() {
  135. cin >> n >> m;
  136. F.init( 3000000 );
  137. for( int i = 1 , u , v ; i < n ; ++ i ) {
  138. scanf("%d%d",&u,&v);
  139. G[u].push_back( v ) , G[v].push_back( u );
  140. E[i] = mp( u , v );
  141. }
  142. dep[1] = 1 , dfs( 1 , 1 );
  143. for( int i = 1 ; i < n ; ++ i )
  144. if( g[E[i].fi][0] == E[i].se ) tt[i] = T[E[i].fi];
  145. else tt[i] = T[E[i].se];
  146. for( int i = 1 , u , v ; i <= m ; ++ i ) {
  147. scanf("%d%d",&u,&v);
  148. S[i] = F.Add( 1 , ++ cn , 1 );
  149. link( cn , u , v );
  150. }
  151. cout << F.maxflow( 1 , 2 ) << endl;
  152. for( int i = 1 ; i <= m ; ++ i ) bacs[S[i]] = i;
  153. for( int i = 1 ; i < n ; ++ i ) bact[tt[i]] = i;
  154. F.work( 1 );
  155. for( int i = F.head[1] ; i ; i = F.nxt[i] ) if( !F.vis[F.to[i]] )
  156. s.push_back( bacs[i ^ 1] );
  157. // F.work( 2 );
  158. for( int i = F.head[2] ; i ; i = F.nxt[i] ) if( F.vis[2] ^ F.vis[F.to[i]] )
  159. t.push_back( bact[i] );
  160. cout << s.size() << ' '; for( auto i : s ) printf("%d ",i); puts("");
  161. cout << t.size() << ' '; for( auto i : t ) printf("%d ",i); puts("");
  162. }

CF 786 E ALT的更多相关文章

  1. cf 786 B 线段树优化建图

    cf 786 B 链接 CF 思路 n个点,3种建边方式,规模\(O(n^2)\) 线段树优化建图 注意 读入的数据好坑啊,说好的v,u变成了u,v. 两棵树,一棵出,一棵入.线段树的作用只不过是按照 ...

  2. puppet介绍与安装

    puppet是什么puppet是一种基于ruby语言开发的Lnux.Unix.windows平台的集中配置管理系统.它使用自有的puppet描述语言,可管理配置文件file.用户user.cron任务 ...

  3. [No000093]按住Alt 再按数字键敲出任意汉字和字符!

    1.在notepad里,(中文系统下) 按住Alt 然后按52946最后放开Alt 按住Alt 然后按45230最后放开Alt 按住Alt 然后按50403最后放开Alt 你会看到"我爱你& ...

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

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

  5. 【机器学习算法-python实现】协同过滤(cf)的三种方法实现

    (转载请注明出处:http://blog.csdn.net/buptgshengod) 1.背景       协同过滤(collaborative filtering)是推荐系统经常使用的一种方法.c ...

  6. 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 ...

  7. 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 ...

  8. [No00008B]远程桌面发送“Ctrl+Alt+Delete”组合键调用任务管理器

    向远程桌面发送"Ctrl+Alt+Delete"组合键的两种方法 1.在本地按下Ctrl+Alt+End,可以成功发送"Ctrl+Alt+Delete"组合键! ...

  9. 平常看到的Alt+xx 快捷键用法

    1. 先按Alt, 哪一个菜单对应的字符是有划线的. 2. 输入对应的字符打开相应的菜单, 3 再输入相应的字符打开子菜单

随机推荐

  1. MacOS安装使用Kettle

    一.环境说明 操作系统版本:macOS Big Sur 11.6.1 机型:Intel版本 JDK版本:Amazon Corretto-openjdk8 Kettle版本:Kettle8.9 二.问题 ...

  2. 面试不再慌,终于有人把TCP讲明白了。。。

    前言 TCP(Transmission Control Protocol,传输控制协议) 是计算机网络的的重要组成部分,也是网络编程的重要内容,还有我们平时接触最多的 HTTP 也是基于 TCP 实现 ...

  3. Seata整合SpringBoot和Mybatis

    Seata整合SpringBoot和Mybatis 一.背景 二.实现功能 三.每个服务使用到的技术 1.账户服务 2.订单服务 四.服务实现 1.账户服务实现 1.引入jar包 2.项目配置 3.建 ...

  4. HttpContext.Current.Request.Url 地址:获取域名

    假设当前页完整地址是:http://www.test.com/aaa/bbb.aspx?id=5&name=kelli 协议名----http://域名  ---- www.test.com站 ...

  5. Notepad++ 过滤注释行和空行

    Notepad++ 删除指定字符开头的行的正则表达式 1.删除A之后的所有字符用:A.*$ 2.删除A之前的所有字符用:^([^s]*)A ####如果是其他字符就把A替换为其他字符 注释:如何是特殊 ...

  6. {% csrf_token %} 原理和作用 (踩坑必看)

    本博客已暂停更新,请转自新博客 https://www.whbwiki.com/320.html 继续阅读 简介 在django中我们需要在templates的form中加入{%csrf_token% ...

  7. C++ Qt 项目实战(一)之文本编辑器

    文本编辑器例图 项目开发环境 系统版本:windows10 QT 版本: 5.9.9 开发语言:C++ 已实现功能 文件操作:新建,打开,保存,另存为,打印,退出 编辑操作:复制,粘贴,剪切,查找,替 ...

  8. win10 python3.8 wxpython.whl 安装步骤

     wxpython是python开发常用图形用户界面(GUI)工具之一,GUI因其直观便捷,对我们提高开发效率一定帮助.这里介绍一下新版本wxPython 4.0.1的安装过程及注意事项. 第1步:下 ...

  9. [jmeter]Jmeter+ant实现接口自动化

    1.安装jmeter 和ant &环境变量配置百度去~ 2.jmeter和ant关联 &将JMeter所在目录下extras子目录里的ant-JMeter-1.1.1.jar复制到an ...

  10. Java学习(二十二)

    学了一个在css中叫font的样式: 感觉还是挺好用的 不过要注意如果把font放在最后,其他会使用默认值,可能会覆盖掉前面的 例如新学的行高 在font中语法是 font:30px/40px &qu ...