保序回归论文题

要求某一个边集为原图的最小生成树,这等价于非树边比所在环(指树上)的所有边小,最大生成树类似

将这些大小关系的限制看作一张有向图,即若要求$w_{i}\le w_{j}$则连边$(i,j)$,设$w_{i}$为初始边权,即要求构造$f_{i}$满足$\forall (i,j)\in E,f_{i}\le f_{j}$,之后最小化$\sum |w_{i}-f_{i}|$

(虽然论文中要求这些大小关系构成DAG,但不构成DAG并不影响结论的证明)

引理:定义集合$S=\{w_{i}\}$,则存在一组最优解满足$\forall i,f_{i}\in S$

证明:考虑对于一组最优解$f_{i}$,若存在$f_{i}\notin S$,选择其中一个$x=f_{i}$,令$U=\{i|f_{i}=x\}$

考虑对于$U$中的点,同时加减1后不影响正确性(因为没有和他相同的数字,且限制包含等号),且由于$x\notin S$,设加1后代价加$\Delta$,则减1后代价加$-\Delta$

不难证明$\min(\Delta,-\Delta)\le 0$,因此对其进行操作不劣(特别的,当$\Delta=0$时,选择加1)

重复执行该操作,证明至多执行有限次操作(无法执行即不存在$f_{i}\notin S$)

称这样一个操作为$f(U,\pm 1)$,则对于一个$U$,不可能同时存在$f(U,1)$和$f(U,-1)$

反证法,假设存在两种操作,不妨假设先执行了$f(U,1)$,然后执行了$f(U,-1)$

注意到若$f(U,1)$会使代价增加$\Delta$,则$f(U,-1)$会使代价增加$-\Delta$,且由于操作后不劣,因此两者都非负,即$\Delta=0$,而当$\Delta=0$时会选择加1,与假设矛盾

称$sum(U)$为对集合$U$的操作次数,若$U$非空且$sum(U)$为无限大,则对于$x\in U$,$|f_{x}-w_{x}|$也为无限大,而初始的答案为有限的,与操作不劣矛盾

$\sum_{U\neq\emptyset}sum(U)$即为总操作次数,由于$U$和$sum(U)$均为有限的,即结果也有限

结论:对于一个非空区间$(a,b)$满足$S\cap (a,b)=\empty$,设$g_{i}$为强制$f_{i}\in \{a,b\}$时的一组最优解,则存在一组最优解$f_{i}$满足若$g_{i}=a$则$f_{i}\le a$、若$g_{i}=b$则$f_{i}\ge b$

证明:考虑一组最优解$f_{i}$,根据引理,不妨强制$f_{i}\in S$,之后存在$g_{i}=a$且$f_{i}>a$($g_{i}=b$且$f_{i}<b$类似,这里就不考虑了)

根据$f_{i}\in S$且$S\cap (a,b)=\empty$,可得若$f_{i}>a$则$f_{i}\ge b$

令$x=\min_{g_{i}=a且f_{i}\ge b}f_{i}$,构造$U=\{i|g_{i}=a且f_{i}=x\}$,再构造代价函数$f(x)=\sum_{i\in U}|w_{i}-x|$

首先,我们将所有$f_{i}$(其中$i\in U$)变为$y$(其中$a\le y\le x$)是合法的,因为这是减小,只需要考虑$j$到$i$的边,分两类讨论:

1.$j\in U$,此时由于全部改变为$y$,显然合法;

2.$j\notin U$,根据$g_{i}$和$f_{i}$为最优解,那么必然是合法的,即$g_{j}\le g_{i}$且$f_{j}\le f_{i}$

进一步的,由于$g_{j}\in \{a,b\}$因此$g_{j}=a$,由于$j\notin U$因此$f_{j}<f_{i}$,那么当$f_{j}>a$则$f_{j}\ge b$,同时$f_{j}<f_{i}$,那么$x$应该为$f_{j}$,矛盾

由此,$f_{j}\le a\le y$,即合法

根据$f_{i}$为最优解,因此改为$y$都不优于留在$x$,即$\forall a\le y\le x,f(x)\le f(y)$

类似的,我们将所有$g_{i}$都变为$b$也是合法的,而$g_{i}$为最优解,即$f(a)\le f(b)$

不难发现$f(x)$是一个下凸函数,而根据上述两个性质,有$f(x)\le f(b)$且$f(a)\le f(b)$(其中$a\le b\le x$),因此只能取到等号,即$f(x)=f(a)=f(b)$

重复执行此操作,即将$f_{i}$都变为$a$或$g_{i}$都变为$b$(两者任选一个都可以),不合法的点对数量严格减少,因此必然可以使得其不存在此类点,且两者仍为最优解,即结论成立

根据这个结论,将所有$w_{i}$排序并离散(去除相同的位置,因为要求非空),求出$g_{i}\in \{w_{mid},w_{mid+1}\}$的解后,即可判定(某一组)最优解$f_{i}$所有元素是小于等于$w_{mid}$还是大于等于$w_{mid+1}$,分治即可

关于如何求出$g_{i}\in \{w_{mid},w_{mid+1}\}$,先贪心分配$g_{i}$(不考虑合法性),将$S$连向选择$w_{mid+1}$的点,选择$w_{mid}$的点连向$T$,代价都为换为另一种后增加的代价,之后通过最小割求出最少要增大多少的代价

对于$(i,j)\in E$,不能有$g_{i}=w_{mid+1}$且$g_{j}=w_{mid}$,因此直接连边$(i,j)$,表示两者中必须修改一个,之后最跑最大流即可,并根据残余网络求出方案

关于求最小割方案:从源点开始搜索,能被搜到(只走流量非0的边)的点即可作为最小割中与$S$相连的点,之后另一部分作为$T$相连的点,两个点集之间的边割掉即可

时间复杂度为$o(nm^{3}\log_{2}m)$,由于网络流常数较小,可以通过

  1. 1 #include<bits/stdc++.h>
  2. 2 using namespace std;
  3. 3 #define N 1005
  4. 4 #define ll long long
  5. 5 #define oo 0x3f3f3f3f
  6. 6 #define vi vector<int>
  7. 7 struct ji{
  8. 8 int nex,to,len;
  9. 9 }edge[N*N];
  10. 10 queue<int>q;
  11. 11 vector<int>st,v;
  12. 12 map<int,int>mat;
  13. 13 map<int,int>::iterator it;
  14. 14 int E,n,head[N],vis[N],work[N],d[N],w[N],a[N],bl[N],ans[N],lim[N][N];
  15. 15 bool cmp(int x,int y){
  16. 16 return bl[x]<bl[y];
  17. 17 }
  18. 18 void init(){
  19. 19 E=0;
  20. 20 memset(head,-1,sizeof(head));
  21. 21 }
  22. 22 void add(int x,int y,int z){
  23. 23 edge[E].nex=head[x];
  24. 24 edge[E].to=y;
  25. 25 edge[E].len=z;
  26. 26 head[x]=E++;
  27. 27 }
  28. 28 void dfs(int k,int fa,int ed,int x,int p){
  29. 29 if (k==ed){
  30. 30 for(int i=0;i<st.size();i++)
  31. 31 if (!p)lim[st[i]][x]=1;
  32. 32 else lim[x][st[i]]=1;
  33. 33 }
  34. 34 for(int i=head[k];i!=-1;i=edge[i].nex)
  35. 35 if (edge[i].to!=fa){
  36. 36 st.push_back(edge[i].len);
  37. 37 dfs(edge[i].to,k,ed,x,p);
  38. 38 st.pop_back();
  39. 39 }
  40. 40 }
  41. 41 bool bfs(){
  42. 42 memset(d,oo,sizeof(d));
  43. 43 d[0]=0;
  44. 44 q.push(0);
  45. 45 while (!q.empty()){
  46. 46 int k=q.front();
  47. 47 q.pop();
  48. 48 for(int i=head[k];i!=-1;i=edge[i].nex)
  49. 49 if ((edge[i].len)&&(d[edge[i].to]==oo)){
  50. 50 d[edge[i].to]=d[k]+1;
  51. 51 q.push(edge[i].to);
  52. 52 }
  53. 53 }
  54. 54 return d[n+1]<oo;
  55. 55 }
  56. 56 int dfs(int k,int s){
  57. 57 if (k>n)return s;
  58. 58 for(int &i=work[k];i!=-1;i=edge[i].nex)
  59. 59 if ((edge[i].len)&&(d[edge[i].to]==d[k]+1)){
  60. 60 int p=dfs(edge[i].to,min(s,edge[i].len));
  61. 61 if (p){
  62. 62 edge[i].len-=p;
  63. 63 edge[i^1].len+=p;
  64. 64 return p;
  65. 65 }
  66. 66 }
  67. 67 return 0;
  68. 68 }
  69. 69 void dinic(){
  70. 70 while (bfs()){
  71. 71 memcpy(work,head,sizeof(work));
  72. 72 while (dfs(0,oo));
  73. 73 }
  74. 74 }
  75. 75 void dfs(int k){
  76. 76 if (vis[k])return;
  77. 77 vis[k]=1;
  78. 78 for(int i=head[k];i!=-1;i=edge[i].nex)
  79. 79 if (edge[i].len)dfs(edge[i].to);
  80. 80 }
  81. 81 void dfs(int l,int r,int x,int y){
  82. 82 if (x==y){
  83. 83 for(int i=l;i<=r;i++)ans[a[i]]=v[x];
  84. 84 return;
  85. 85 }
  86. 86 int mid=(x+y>>1);
  87. 87 init();
  88. 88 for(int i=l;i<=r;i++){
  89. 89 int wx=abs(w[a[i]]-v[mid]),wy=abs(w[a[i]]-v[mid+1]);
  90. 90 if (wx>wy){
  91. 91 bl[a[i]]=1;
  92. 92 add(0,i+1,wx-wy);
  93. 93 add(i+1,0,0);
  94. 94 }
  95. 95 else{
  96. 96 bl[a[i]]=0;
  97. 97 add(i+1,n+1,wy-wx);
  98. 98 add(n+1,i+1,0);
  99. 99 }
  100. 100 }
  101. 101 for(int i=l;i<=r;i++)
  102. 102 for(int j=l;j<=r;j++)
  103. 103 if (lim[a[i]][a[j]]){
  104. 104 add(i+1,j+1,oo);
  105. 105 add(j+1,i+1,0);
  106. 106 }
  107. 107 dinic();
  108. 108 memset(vis,0,sizeof(vis));
  109. 109 dfs(0);
  110. 110 assert(!vis[n+1]);
  111. 111 for(int i=head[0];i!=-1;i=edge[i].nex)
  112. 112 if (!vis[edge[i].to])bl[a[edge[i].to-1]]=0;
  113. 113 for(int i=head[n+1];i!=-1;i=edge[i].nex)
  114. 114 if (vis[edge[i].to])bl[a[edge[i].to-1]]=1;
  115. 115 sort(a+l,a+r+1,cmp);
  116. 116 for(int i=l;i<=r+1;i++){
  117. 117 if ((bl[a[i]])||(i>r)){
  118. 118 if (l<i)dfs(l,i-1,x,mid);
  119. 119 if (i<=r)dfs(i,r,mid+1,y);
  120. 120 return;
  121. 121 }
  122. 122 }
  123. 123 }
  124. 124 class ExtremeSpanningTrees{
  125. 125 public:
  126. 126 ll minTime(vi ea,vi eb,vi ec,vi mn,vi mx){
  127. 127 n=ea.size();
  128. 128 init();
  129. 129 for(int i=0;i<mn.size();i++){
  130. 130 add(ea[mn[i]],eb[mn[i]],mn[i]);
  131. 131 add(eb[mn[i]],ea[mn[i]],mn[i]);
  132. 132 vis[mn[i]]=1;
  133. 133 }
  134. 134 for(int i=0;i<n;i++)
  135. 135 if (!vis[i])dfs(ea[i],-1,eb[i],i,0);
  136. 136 init();
  137. 137 memset(vis,0,sizeof(vis));
  138. 138 for(int i=0;i<mx.size();i++){
  139. 139 add(ea[mx[i]],eb[mx[i]],mx[i]);
  140. 140 add(eb[mx[i]],ea[mx[i]],mx[i]);
  141. 141 vis[mx[i]]=1;
  142. 142 }
  143. 143 for(int i=0;i<n;i++)
  144. 144 if (!vis[i])dfs(ea[i],-1,eb[i],i,1);
  145. 145 for(int i=0;i<n;i++)mat[w[i]=ec[i]]=1;
  146. 146 for(it=mat.begin();it!=mat.end();it++)v.push_back((*it).first);
  147. 147 for(int i=0;i<n;i++)a[i]=i;
  148. 148 dfs(0,n-1,0,v.size()-1);
  149. 149 for(int i=0;i<n;i++)
  150. 150 for(int j=0;j<n;j++)
  151. 151 if (lim[i][j])assert(ans[i]<=ans[j]);
  152. 152 ll sum=0;
  153. 153 for(int i=0;i<n;i++)sum+=abs(ans[i]-w[i]);
  154. 154 return sum;
  155. 155 }
  156. 156 };

[tc14634]ExtremeSpanningTrees的更多相关文章

  1. [loj3301]魔法商店

    令$A=\{a_{1},a_{2},...,a_{s}\}$,若$k\not\in A$,那么恰存在一个$A'\subseteq A$使得$c_{k}=\bigoplus_{x\in A'}c_{x} ...

  2. 退役前的最后的做题记录upd:2019.04.04

    考试考到自闭,每天被吊打. 还有几天可能就要AFO了呢... Luogu3602:Koishi Loves Segments 从左向右,每次删除右端点最大的即可. [HEOI2014]南园满地堆轻絮 ...

  3. [loj2470]有向图

    参考ExtremeSpanningTrees,考虑优化整体二分时求$g_{i}\in \{w_{mid},w_{mid+1}\}$的最优解 对于$m=n-1$的问题,不需要去网络流,可以直接树形dp ...

  4. [loj6518]序列

    参考ExtremeSpanningTrees,考虑优化整体二分时求$g_{i}\in \{w_{mid},w_{mid+1}\}$的最优解 首先题目有一个条件似乎没有写出来,是保证$l\le k\le ...

随机推荐

  1. FastAPI(64)- Settings and Environment Variables 配置项和环境变量

    背景 在许多情况下,应用程序可能需要一些外部设置或配置,例如密钥.数据库凭据.电子邮件服务凭据等. 大多数这些设置都是可变的(可以更改),例如数据库 URL,很多可能是敏感数据,比如密码 出于这个原因 ...

  2. 利用PATH环境变量 - 提升linux权限~👻

    利用PATH提升linux权限 参考地址:https://www.hackingarticles.in/linux-privilege-escalation-using-path-variable/ ...

  3. 基本的bash shell命令

    目录 基本的bash shell命令 启动shell shell提示符 基本的bash shell命令 启动shell GNU bash shell 能提供对Linux系统的交互式访问.它是作为普通程 ...

  4. [no code][scrum meeting] Beta 6

    $( "#cnblogs_post_body" ).catalog() 例会时间:5月19日11:30,主持者:黎正宇 下次例会时间:5月20日11:30,主持者:彭毛小民 一.工 ...

  5. 【二食堂】Beta - Scrum Meeting 5

    Scrum Meeting 5 例会时间:5.18 18:30~18:50 进度情况 组员 当前进度 今日任务 李健 1. 划词功能已经实现,继续开发,完善文本区域交互,调用API issue 1. ...

  6. 软件案例分析——VS、VS Code

    软件案例分析--VS和VS Code 第一部分 调研,测评 一.使用10–30分钟这个软件的基本功能(请上传使用软件的照片) VS code Visual Studio 二.主要功能和目标用户有何不同 ...

  7. Noip模拟31 2021.8.5

    T1 Game 当时先胡了一发$\textit{Next Permutation}$... 然后想正解,只想到贪心能求最大得分,然后就不会了.. 然后就甩个二十分的走了... 正解的最大得分(叫它$k ...

  8. 玩转C语言链表-链表各类操作详解

    链表概述 链表是一种常见的重要的数据结构.它是动态地进行存储分配的一种结构.它可以根据需要开辟内存单元.链表有一个"头指针"变量,以head表示,它存放一个地址.该地址指向一个元素 ...

  9. 计算机网络传输层之TCP流量控制

    文章转自:https://blog.csdn.net/weixin_43914604/article/details/105531547 学习课程:<2019王道考研计算机网络> 学习目的 ...

  10. 字符串与模式匹配算法(二):MP算法

    一.MP算法介绍 MP 算法(Morris-Pratt算法)是一种快速串匹配算法,它是詹姆斯·莫里斯(James Morris)和沃恩·普莱特(Vaughan Pratt)在1970年提出的一种快速匹 ...