前言
来自山西队爷的分享题。
思路分析
首先有一个朴素的想法,能否枚举两个集合的边权,判断是否合法。
发现是可以的。
具体地,我们设 \(D(A)=w_1,D(B)=w_2\),不失一般性,假设 \(w_1 \ge w_2\)。
这样,我们可以把图上的边 \((x,y,w)\) 分成三类:
-
\(w \le w_2\):没有影响;
-
\(w2<w\le w_1\):\(x,y\) 不能同时在 \(B\) 集合中;
-
\(w>w_1\):\(x,y\) 不能同时在一个集合中。
发现限制很像一个 2-sat 问题,考虑将 \(x\) 拆成 \(x',x\),分别表示在 \(A,B\) 集合中。
-
对于不能同时在 \(B\) 集合的点,\(x\to y'\),\(y \to x'\);
-
对于不能同时在一个集合中的点,\(x\to y'\),\(y\to x'\),\(x' \to y\),\(y' \to x\)。
然后直接 tarjan 判定是否合法。
复杂度 \(O(n^6)\)。
能不能再给力一点啊?
大胆猜测单调性,也就是 \(w_1\) 递增时,合法的 \(w_2\) 递减,这样可以双指针维护。
复杂度 \(O(n^4)\)。
能不能再给力一点啊?
考虑对于不能在同一个集合的限制,实际上也太严苛了。
考虑从大到小枚举 \(w_1\),二分求出 \(w_2\) 的过程中,我们在线维护 \(w \ge w_1\) 的边的连通性,如果当前边连上出现环,分类讨论:
-
如果是奇环,那么以后所有的边都加不进去了,考虑做完这次直接终止;
-
如果是偶环,那么图的联通性并没有改变,二分出的 \(w_2\) 结果不会改变,直接更新答案就行。
判断环的奇偶性可以带权并查集。
分析我们的复杂度,我们本质不同的 \(w_1\) 只有 \(O(n)\) 个。
复杂度 \(O(n^3 \log n)\),常数不大,可以通过。
代码实现
要特别注意 \(0\) 的问题。
#include<bits/stdc++.h>
using namespace std;
const int inf=2e9+10;
int n,m,cnt,p,ans,v;
struct node{int x,y,w;
}h[40005];
bool cmp(node a,node b){return a.w<b.w;
}
int fa[205],w[205];
void init(){for(int i=1;i<=n;i++){fa[i]=i;}
}
int find(int x){if(fa[x]==x) return x;int y=find(fa[x]);w[x]^=w[fa[x]];fa[x]=y;return y;
}
void merge(int x,int y){int fx=find(x),fy=find(y);if(fx==fy) return;fa[fy]=fx;w[fy]=w[x]^w[y]^1;
}
int head[405],nxt[400005],target[400005],tot;
void add(int x,int y){tot++;nxt[tot]=head[x];head[x]=tot;target[tot]=y;
}
int dfn[405],low[405],vis[405],col[405],dcnt,ccnt;
stack<int> s;
void tarjan(int x){dfn[x]=low[x]=++dcnt;vis[x]=1;s.push(x);for(int i=head[x];i;i=nxt[i]){int y=target[i];if(!dfn[y]){tarjan(y);low[x]=min(low[x],low[y]);}else if(vis[y]) low[x]=min(low[x],dfn[y]);}if(dfn[x]==low[x]){ccnt++;col[x]=ccnt;vis[x]=0;while(s.top()!=x){int y=s.top();s.pop();col[y]=ccnt;vis[y]=0;}s.pop();}
}
bool check(int w1,int w2){for(int i=1;i<=(n<<1);i++){head[i]=dfn[i]=low[i]=vis[i]=col[i]=0;}dcnt=ccnt=tot=0;for(int i=1;i<=cnt;i++){if(h[i].w<=w2){continue;}else if(h[i].w>w1){add(h[i].x,h[i].y+n);add(h[i].y+n,h[i].x);add(h[i].y,h[i].x+n);add(h[i].x+n,h[i].y);}else{add(h[i].x,h[i].y+n);add(h[i].y,h[i].x+n);}}for(int i=1;i<=(n<<1);i++){if(!dfn[i]) tarjan(i);}for(int i=1;i<=n;i++){if(col[i]==col[i+n]) return false;}return true;
}
int find(int l,int r,int w){if(l==r){if(check(w,h[l].w)) return l;else return -1;}int mid=(l+r)>>1;if(check(w,h[mid].w)) return find(l,mid,w);else return find(mid+1,r,w);
}
int main(){ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cin>>n; for(int i=1;i<=n;i++){for(int j=i+1;j<=n;j++){cin>>v;h[++cnt]=(node){i,j,v};}}sort(h+1,h+1+cnt,cmp);if(check(0,0)){cout<<0;return 0;}p=0,ans=inf;init();for(int i=cnt;i>=1;i--){if(find(h[i].x)==find(h[i].y)){if(w[h[i].x]==w[h[i].y]){p=find(p,cnt,h[i].w);if(p!=-1) ans=min(ans,h[i].w+h[p].w);break;}else ans=min(ans,h[i].w+h[p].w);}else{merge(h[i].x,h[i].y);p=find(p,cnt,h[i].w);if(p==-1) break;ans=min(ans,h[i].w+h[p].w);}}cout<<ans;return 0;
}