[JZOJ5386]碎
来源:互联网 发布:overlay网络 是什么 编辑:程序博客网 时间:2024/04/27 22:44
题目大意
给你一个带边权完全图,要求你分成两个联通块,联通块的贡献定义为块内最大边权,求最小的贡献和。
n<=300。
答案在int范围内。
分析
考虑暴力,我们枚举一条边,代表贡献较大的联通块的最大边权,较小贡献的联通块的最大边可以二分得到贡献。在一种情况下,比较大边权更大的边的两端的点要处于不同的联通块,处于较大和较小边贡献之间的边的端点不能同时属于较小贡献联通块。这个是一个2-SAT问题。
2-SAT判断有解问题
我们把一个点x拆成两个点,x0,x1,到时候我们选且只能选一个点,代表他属于哪个集合。我定义0集合为贡献较小集合。新图是个有向图,一条有向边(u,v)代表如果选了u必须选v。
那么前面的条件,对于原边(u,v),如果是第一种情况,我们给u0,v1连两条相互的有向边,u1,v0也是;第二种情况,我们连(u0,v1),(v0,u1)。
判断有解,我们可以强联通分量缩点。如果一个原来的点x的x0,x1同时属于同一个集合,那么一定无解。
这道题我们直接这样即可。
2-SAT跑可行解
顺便讲一下。
缩点之后,得到DAG,我们按逆拓扑序遍历DAG(其实就是tarjan缩点的编号从小到大的顺序)。遇到一个强联通分量,如果被标记为不选,我们跳过它;如果没有被标记为不选,那我们选择它,即选择里面所有的点,x0,y1,z0…之类的。这之后把所有x1,y0,z1…所在的强联通分量标记为不选。这样一定能出解。
原题优化
原来做法要
我们从大到小枚举,假设有tot条边,现在枚举到第i条边(x,y),那么假如他和i+1~tot的边构成了一个偶环,那这条边不用判断,因为x和y一定只能处于不同集合。假如是奇环,那么做完他我们可以直接退出,因为x,y只能处于同一个集合,不退出就意味着x,y又要满足处于不同集合的条件,和之前矛盾。
这个我们用并查集染色可以维护。
二分次大边的时候我们可以利用单调性,让二分下界l=上一次二分的次大边。(不理解自己想一想)
这样就是
代码
#include<cstdio>#include<algorithm>#include<cmath>#include<cstring>#include<set>using namespace std;#define fo(i,j,k) for(i=j;i<=k;i++)#define fd(i,j,k) for(i=j;i>=k;i--)#define cmax(a,b) (a=(a>b)?a:b)#define cmin(a,b) (a=(a<b)?a:b)typedef long long ll;typedef double db;const int N=5e5+5,mo=1e9+7;struct rec{ int x,y,z;}b[N];int fa[N],col[N],rx,ry,x,y,z,pdd,st,sta[N],df,dfn[N],low[N],td,tag[N],i,n,ref[N],tb,l,r,j,ans;int vis[N],first[N],b1[N],next[N],tt,kan,r0,mid,pp;bool operator <(rec a,rec b){ return a.z<b.z;}void cr(int x,int y){ tt++; b1[tt]=y; next[tt]=first[x]; first[x]=tt;}int get(int x){ if (fa[x]==x) return x; int tmp=get(fa[x]); col[x]^=col[fa[x]]; return fa[x]=tmp;}void tarjan(int x){ vis[x]=1; sta[++st]=x; low[x]=dfn[x]=++df; for(int p=first[x];p;p=next[p]) { if (vis[b1[p]]==2) continue; if (!vis[b1[p]]) { tarjan(b1[p]); cmin(low[x],low[b1[p]]); }else cmin(low[x],dfn[b1[p]]); if (!pdd) return ; } if (low[x]==dfn[x]) { ++td; while (sta[st+1]!=x) { tag[sta[st]]=td; if (tag[ref[sta[st]]]==td) { pdd=0; return ; } vis[sta[st]]=2; st--; } }}void clear(){ td=0;st=0;tt=0;df=0; fo(i,1,n*2) first[i]=tag[i]=vis[i]=0;}int pd(int l){ clear();// vis ,edges,df fo(i,r+1,tb) { x=b[i].x;y=b[i].y; cr(x,y+n);cr(y+n,x); cr(x+n,y);cr(y,x+n); } fo(i,l+1,r-1) { x=b[i].x;y=b[i].y; cr(x,y+n); cr(y,x+n); } pdd=1; fo(i,1,n*2) if (!vis[i]) { tarjan(i); if (!pdd) return 0; } return 1;}int main(){ freopen("t1.in","r",stdin);// freopen("broken.out","w",stdout); scanf("%d",&n); fo(i,1,n-1) fo(j,1,n-i) { scanf("%d",&x); b[++tb]={i,i+j,x}; } fo(i,1,n) { ref[i]=i+n; ref[i+n]=i; } sort(b+1,b+1+tb); ans=b[tb].z; fo(i,1,n) fa[i]=i; l=1; fd(r,tb,1) { x=b[r].x; y=b[r].y; z=b[r].z; rx=get(x);ry=get(y); if (rx==ry) { if (col[x]==col[y]) pp=1; else continue; }else fa[rx]=ry,col[rx]=col[x]^col[y]^1; kan++; r0=r; while (l<r0) { mid=(l+r0)/2; if (!pd(mid)) l=mid+1; else r0=mid; } if (l>=r) break; cmin(ans,z+b[l].z); if (pp) break; } printf("%d\n",ans);}
- [JZOJ5386]碎
- 碎
- 碎
- 碎纸片
- 碎了
- 碎碎碎
- 碎月
- 碎凌霄
- 碎纸片
- 碎语收藏
- l流年碎影
- 玻璃碎了
- 稀碎的时光
- 腊八碎语
- 七月碎语
- 恋爱碎语
- 项目碎想
- 戏子碎流年
- 51 nod 1378 夹克老爷的愤怒 树形dp + 贪心
- saturate_cast<>()
- qt5.5 webview无法显示百度网页等
- react-native学习之路-安装开源的tab-navigator出错return response error code:500
- 【NOIP2017提高A组模拟10.6】Biology
- [JZOJ5386]碎
- 2.3OpenCV程序计时
- lr录制脚本为空/Action为0
- vim 编辑器的使用
- Spring Boot参考教程(八)日志相关使用
- SQL Server,MySQL,Oracle三者的区别
- C++ 多线程
- JZOJ3473. 铺砖问题 (2017.10B组)
- zookeeper与kafka介绍