[cf1615G]Maximum Adjacent Pairs
考虑所有极长的0,对其长度分类讨论——
1.若其长度为$2m+1$,总是将首/尾与相邻的非0元素配对,其余元素配成$m$对
同时,若首尾中某一个元素对应的$k$已经出现,那么必然与另一个配对
2.若其长度为$2m$,总是配成$m$对或将首/尾均与相邻的非0元素配对,其余元素配成$m-1$对
同时,若首尾中某一个元素对应的$k$已经出现,那么必然直接配成$m$对
处理完必然的情况后,不妨仅考虑第1种情况的选择——
将首尾相邻的非0元素连边,即对每一条边选择一个端点并最大化选择的集合
显然每一个连通块是独立的,考虑其中一个连通块:
1.若其为树,任选一点为根并对每一条边选择儿子,即仅有根未被选择
注意到根是任意的,且由于边数$<$点数,因此不可能使所有点均被选择(已经最优)
2.若其不为树,求生成树后额外选一条边即可,即所有节点均被选择
进一步的,考虑结合第2种情况(指长度为$2m$)的选择——
同样将首尾相邻的非0元素连边,对于所有选择后者的边,若在同一颗树(指第1种情况中)出现两次显然不优
换言之,将第1种情况中的树上所有点缩点,问题即求此时的最大匹配
这张图中有$o(A)$个点和$o(n)$条边(其中$A=\max_{i=1}^{n}a_{i}$),直接使用带花树算法即可
关于带花树算法,具体即类似匈牙利算法,并当dfs过程中发现奇环时将奇环缩点
通过调整旋转方向,可以使得新图中的增广路也在原图中存在(反之显然),正确性即得证
关于实现方式,略微比较复杂,具体如下——
通常使用bfs代替dfs,并对增广路上(当前)非匹配边中远离起点的点记录另一个点
当发现奇环时,由于之后还需要得到方案,需要将非匹配边的"另一个点"也记录对应的另一个点(即相互记录)
设当前搜到的(非匹配边)为$(x,y)$,将两点交替向上爬(类似求lca),至多多爬一次即可得到该环
另外,对于环上直接通过匹配边拓展的点,其余边也可以拓展,需要重新加入队列
时间复杂度(我觉得)为$o(|V||E|)$,可以通过
时间复杂度为$o(An)$,可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 300005 4 #define M 605 5 #define fi first 6 #define se second 7 struct Edge{ 8 int nex,to,tp; 9 }edge[N<<1]; 10 pair<int,int>v[N]; 11 queue<int>q; 12 vector<int>bl[M]; 13 int n,m,n0,V,E,x,y,a[N],id[N],visc[N],vis0[N],head[M],vis[M],pos[M],rt[M],fr[M],fa[M],bj[M],pre[M],match[M]; 14 //visc[i]=1当且仅当第i种颜色被使用(1<=i<M-4) 15 //vis0[i]=1当且仅当第i段已经被完全确定 16 void add(int x,int y,int z){ 17 edge[E]=Edge{head[x],y,z}; 18 head[x]=E++; 19 } 20 void dfs1(int k,int fa){ 21 if (pos[k]){ 22 rt[V]=k,fr[V]=fa; 23 return; 24 } 25 pos[k]=V; 26 for(int i=head[k];i!=-1;i=edge[i].nex) 27 if (edge[i].tp!=fa)dfs1(edge[i].to,edge[i].tp); 28 } 29 void dfs2(int k,int fa){ 30 if (vis[k])return; 31 vis[k]=1; 32 if (fa){ 33 vis0[fa]=1; 34 x=v[fa].fi,y=v[fa].se; 35 if (a[x-1]==k){ 36 a[x]=k; 37 for(int i=x+1;i<=y;i+=2)a[i]=a[i+1]=id[n0--]; 38 } 39 else{ 40 a[y]=k; 41 for(int i=x;i<y;i+=2)a[i]=a[i+1]=id[n0--]; 42 } 43 } 44 for(int i=0;i<bl[k].size();i++){ 45 if (vis0[bl[k][i]])continue; 46 x=v[bl[k][i]].fi,y=v[bl[k][i]].se; 47 if ((y-x)&1){ 48 vis0[bl[k][i]]=1; 49 for(int i=x;i<=y;i+=2)a[i]=a[i+1]=id[n0--]; 50 } 51 } 52 for(int i=head[k];i!=-1;i=edge[i].nex) 53 if (edge[i].tp!=fa)dfs2(edge[i].to,edge[i].tp); 54 } 55 int find(int k){ 56 if (k==fa[k])return k; 57 return fa[k]=find(fa[k]); 58 } 59 int lca(int x,int y){ 60 bj[0]++,x=find(x),y=find(y); 61 while (bj[x]!=bj[0]){ 62 bj[x]=bj[0],x=find(pre[match[x]]); 63 if (y)swap(x,y); 64 } 65 return x; 66 } 67 void merge(int k,int lst,int x){ 68 while (find(k)!=x){ 69 pre[k]=lst,lst=match[k]; 70 if (find(k)==k)fa[k]=x; 71 if (find(lst)==lst)fa[lst]=x; 72 if (vis[lst]>0){ 73 vis[lst]=0; 74 q.push(lst); 75 } 76 k=pre[lst]; 77 } 78 } 79 void bfs(int k){ 80 memset(vis,-1,sizeof(vis)); 81 memset(pre,0,sizeof(pre)); 82 for(int i=1;i<=V;i++)fa[i]=i; 83 while (!q.empty())q.pop(); 84 vis[k]=0,q.push(k); 85 while (!q.empty()){ 86 int k=q.front(); 87 q.pop(); 88 for(int i=head[k];i!=-1;i=edge[i].nex){ 89 int x=edge[i].to; 90 if ((find(k)==find(x))||(vis[x]>0))continue; 91 if (vis[x]<0){ 92 vis[x]=1,pre[x]=k; 93 if (!match[x]){ 94 while (x){ 95 int y=pre[x],xx=match[y]; 96 match[x]=y,match[y]=x,x=xx; 97 } 98 return; 99 } 100 vis[match[x]]=0,q.push(match[x]); 101 continue; 102 } 103 int z=lca(k,x); 104 merge(k,x,z),merge(x,k,z); 105 } 106 } 107 } 108 void calc1(){ 109 q.push(0); 110 for(int i=1;i<n;i++) 111 if ((a[i])&&(a[i]==a[i+1]))q.push(a[i]); 112 for(int i=1,j=1;i<=n+1;i++) 113 if ((i>n)||(a[i])){ 114 if (j<i){ 115 v[++m]=make_pair(j,i-1); 116 bl[a[j-1]].push_back(m); 117 bl[a[i]].push_back(m); 118 } 119 j=i+1; 120 } 121 while (!q.empty()){ 122 int k=q.front(); 123 q.pop(); 124 if (k)visc[k]=1; 125 for(int i=0;i<bl[k].size();i++){ 126 if (vis0[bl[k][i]])continue; 127 vis0[bl[k][i]]=1; 128 x=v[bl[k][i]].fi,y=v[bl[k][i]].se; 129 if ((y-x)&1){ 130 for(int i=x;i<=y;i+=2)a[i]=a[i+1]=id[n0--]; 131 } 132 else{ 133 if (a[x-1]!=k){ 134 q.push(a[x-1]),a[x]=a[x-1]; 135 for(int i=x+1;i<=y;i+=2)a[i]=a[i+1]=id[n0--]; 136 } 137 if (a[y+1]!=k){ 138 q.push(a[y+1]),a[y]=a[y+1]; 139 for(int i=x;i<y;i+=2)a[i]=a[i+1]=id[n0--]; 140 } 141 if ((a[x-1]==k)&&(a[y+1]==k)){ 142 a[y]=1; 143 for(int i=x;i<y;i+=2)a[i]=a[i+1]=id[n0--]; 144 } 145 } 146 } 147 bl[k].clear(); 148 } 149 } 150 void calc2(){ 151 E=0; 152 memset(head,-1,sizeof(head)); 153 memset(pos,0,sizeof(pos)); 154 for(int i=1;i<=m;i++) 155 if (!vis0[i]){ 156 x=v[i].fi,y=v[i].se; 157 if ((y-x+1)&1){ 158 add(a[x-1],a[y+1],i); 159 add(a[y+1],a[x-1],i); 160 } 161 } 162 for(int i=1;i<M-4;i++) 163 if ((!visc[i])&&(!pos[i]))V++,dfs1(i,0); 164 E=0; 165 memset(head,-1,sizeof(head)); 166 memset(match,0,sizeof(match)); 167 for(int i=1;i<=m;i++) 168 if (!vis0[i]){ 169 x=v[i].fi,y=v[i].se; 170 if ((rt[pos[a[x-1]]])||(rt[pos[a[y+1]]]))continue; 171 if ((y-x)&1){ 172 x=pos[a[x-1]],y=pos[a[y+1]]; 173 if (x!=y)add(x,y,i),add(y,x,i); 174 } 175 } 176 for(int i=1;i<=V;i++) 177 if (!match[i])bfs(i); 178 for(int i=1;i<=V;i++) 179 if ((match[i])&&(i<match[i])){ 180 for(int j=head[i];j!=-1;j=edge[j].nex) 181 if (edge[j].to==match[i]){ 182 vis0[edge[j].tp]=1; 183 x=v[edge[j].tp].fi,y=v[edge[j].tp].se; 184 a[x]=rt[pos[a[x-1]]]=a[x-1]; 185 a[y]=rt[pos[a[y+1]]]=a[y+1]; 186 for(int k=x+1;k<y;k+=2)a[k]=a[k+1]=id[n0--]; 187 break; 188 } 189 } 190 E=0; 191 memset(head,-1,sizeof(head)); 192 memset(vis,0,sizeof(vis)); 193 for(int i=1;i<=m;i++) 194 if (!vis0[i]){ 195 x=v[i].fi,y=v[i].se; 196 if ((y-x+1)&1){ 197 add(a[x-1],a[y+1],i); 198 add(a[y+1],a[x-1],i); 199 } 200 } 201 for(int i=1;i<M-4;i++) 202 if ((!visc[i])&&(!rt[pos[i]]))rt[pos[i]]=i; 203 for(int i=1;i<=V;i++)dfs2(rt[i],fr[i]); 204 for(int i=1;i<=m;i++) 205 if (!vis0[i]){ 206 x=v[i].fi,y=v[i].se; 207 if ((y-x)&1){ 208 for(int j=x;j<=y;j+=2)a[j]=a[j+1]=id[n0--]; 209 } 210 else{ 211 a[y]=1; 212 for(int j=x;j<y;j+=2)a[j]=a[j+1]=id[n0--]; 213 } 214 } 215 } 216 int main(){ 217 scanf("%d",&n); 218 for(int i=1;i<=n;i++){ 219 scanf("%d",&a[i]); 220 visc[a[i]]=1; 221 } 222 for(int i=1;i<=n;i++) 223 if (!visc[i])id[++n0]=i; 224 memset(visc,0,sizeof(visc)); 225 calc1(),calc2(); 226 for(int i=1;i<=n;i++)printf("%d ",a[i]); 227 return 0; 228 }