【2-SAT】【AtCoder Regular Contest 069 F】Flag
来源:互联网 发布:运营商的云计算项目 编辑:程序博客网 时间:2024/06/07 05:44
Description
Snuke 喜欢旗子.
Snuke 正在将N 个旗子摆在一条线上.
第i 个旗子可以被放在位置xi 或yi 上.
Snuke 认为两个旗子间的最小距离越大越好. 请你求出最大值.
对于100% 的数据, 1 <= N <= 10^4,1 <= xi, yi <= 10^9.
2-SAT
模型还是比较显然的。看到双最值想到二分,转为判定性问题
我们拆点,b[i][1]表示位置i选,b[i][0]表示不选
这时边的意义就是“推出”,比如说b[xi][0]向b[yi][1]连边,因为xi不放就必然要放yi
考虑限制条件:判定是否有方案,使得选择的点间距>=lim
对于每个点x,如果它选,那么b[x][1]就要向所有的dis(x,y)< lim 的b[y][0]连边,因为一旦选择了x,就不能选与它间距< lim的点
然而这样最坏情况下,边数是
考虑到连边总是向一个去心领域内连,我们有对应的优化方法
分块优化连边
自己yy吧,很简单。这样会多出
线段树优化连边
用线段树上的结点结构来优化,父节点向子节点连边。这样会多出
进行完连边优化之后,边数变成
接着要求解2-SAT
2-SAT问题一般有两个解决方法,都是线性的
有向图的Tarjan算法
对构出的图跑Tarjan,对于任意x判定b[x][0],b[x][1]是否在同一连通块。若是则有矛盾。
不太清楚这种方法如何构造一组可行解。
这个方法复杂度没有任何问题
dfs染色
对于当前遇到的每个未染色的点,尝试染b[x][0],如果不可行再染b[x][1],这样每个点最多被染两次
感性证明:2-SAT问题具有对称性,其本质为原命题与逆否命题的真伪性相同。一个点开始的dfs染色会把它所在的SCC的所有点的0/1确定下来
这样可以通过最后每个点的颜色来构造可行解
可是,我们线段树优化连边时新建了O(n)个点,如果很多个点都dfs重新染色,可能会重复经过这O(n)个点多次。这个复杂度我不太会算,但是这种方法实测很快,在Atcoder上交也过了(虽然说跑得挺慢)
Code
分块优化连边+dfs染色
#include<cmath>#include<cstdio>#include<cstring>#include<algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,b,a) for(int i=b;i>=a;i--)#define efo(i,v,u) for(int i=last[v],u=to[last[v]];i;i=nxt[i],u=to[i])#define max(x,y) ((x)>(y)?(x):(y))#define min(x,y) ((x)<(y)?(x):(y))#define mset(a,x) memset(a,x,sizeof(a))using namespace std;typedef long long ll;void read(int &n){ int t=0,p=1;char ch; for(ch=getchar();!('0'<=ch && ch<='9');ch=getchar()) if(ch=='-') p=-1; for(;'0'<=ch && ch<='9';ch=getchar()) t=t*10+ch-'0'; n=t*p;}const int N=4e5+5,M=50000005;int n,nn,rtn,tot,ext,b[N][2];struct node{ int x,id;}a[N];bool cmp(node a,node b){return a.x<b.x;}int m,co[N],to[M],nxt[M],last[N],list[N],L[N],R[N];void link(int u,int v){ to[++m]=v,nxt[m]=last[u],last[u]=m;}bool dfs(int v){ if(v<=tot && co[v^1]) return 0; if(v<=tot && co[v]) return 1; co[v]=1; list[++list[0]]=v; efo(i,v,u) if(!co[u]) if(!dfs(u)) return 0; return 1;}bool check(int lim){ m=0;mset(last,0); fo(i,1,n) { link(b[i+i-1][0],b[i+i][1]),link(b[i+i][1],b[i+i-1][0]); link(b[i+i-1][1],b[i+i][0]),link(b[i+i][0],b[i+i-1][1]); } fo(i,1,rtn) fo(j,L[i],R[i]) link(tot+i,b[a[j].id][0]); int l=1,r=1; fo(i,1,nn) { while(l<nn && a[i].x-a[l].x>=lim) ++l; while(r<nn && a[r+1].x-a[i].x<lim) ++r; int ql=min(rtn,(l-1)/rtn+1),qr=min(rtn,(r-1)/rtn+1),qi=min(rtn,(i-1)/rtn+1); if(ql==qr) { fo(j,l,r) if(j!=i) link(b[a[i].id][1],b[a[j].id][0]); } else { if(ql==qi) fo(j,l,i-1) link(b[a[i].id][1],b[a[j].id][0]); else { fo(j,l,R[ql]) link(b[a[i].id][1],b[a[j].id][0]); fo(j,ql+1,qi-1) link(b[a[i].id][1],tot+j); fo(j,L[qi],i-1) link(b[a[i].id][1],b[a[j].id][0]); } if(qi==qr) fo(j,i+1,r) link(b[a[i].id][1],b[a[j].id][0]); else { fo(j,i+1,R[qi]) link(b[a[i].id][1],b[a[j].id][0]); fo(j,qi+1,qr-1) link(b[a[i].id][1],tot+j); fo(j,L[qr],r) link(b[a[i].id][1],b[a[j].id][0]); } } } mset(co,0); fo(i,1,tot) { int x=i+i-1; if(!co[b[x][0]] && !co[b[x][1]]) { list[0]=0; if(!dfs(b[x][0])) { fo(j,1,list[0]) co[list[j]]=0; list[0]=0; if(!dfs(b[x][1])) return 0; } } } return 1;}int main(){ freopen("a.in","r",stdin); freopen("a.out","w",stdout); int x,y; read(n);nn=n+n; fo(i,1,n) read(a[i+i-1].x),read(a[i+i].x); tot=1; fo(i,1,nn) a[i].id=i,b[i][0]=++tot,b[i][1]=++tot; rtn=sqrt(nn); fo(i,1,rtn-1) L[i]=1+rtn*(i-1),R[i]=rtn*i; L[rtn]=1+rtn*(rtn-1),R[rtn]=nn; sort(a+1,a+nn+1,cmp); int l=0,r=a[nn].x+1; while(l<r-1) { int mid=(l+r)>>1; if(check(mid)) l=mid; else r=mid; } printf("%d\n",l); return 0;}
线段树优化连边+tarjan判可行
#include<stack>#include<cstdio>#include<cstring>#include<algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,b,a) for(int i=b;i>=a;i--)#define efo(i,v,u) for(int i=last[v],u=to[last[v]];i;i=nxt[i],u=to[i])#define max(x,y) ((x)>(y)?(x):(y))#define min(x,y) ((x)<(y)?(x):(y))#define mset(a,x) memset(a,x,sizeof(a))using namespace std;typedef long long ll;void read(int &n){ int t=0,p=1;char ch; for(ch=getchar();!('0'<=ch && ch<='9');ch=getchar()) if(ch=='-') p=-1; for(;'0'<=ch && ch<='9';ch=getchar()) t=t*10+ch-'0'; n=t*p;}const int N=4e5+5,M=1e7+5;int n,nn,vtot,tot,root,b[N][2];struct node{ int x,id;}a[N];bool cmp(node a,node b){return a.x<b.x;}int m,co[N],to[M],nxt[M],last[N],ls[N],rs[N];void link(int u,int v){ to[++m]=v,nxt[m]=last[u],last[u]=m;}void build(int &v,int l,int r){ if(l==r) { v=b[a[l].id][0]; return; } v=++tot; int mid=l+r>>1; build(ls[v],l,mid);build(rs[v],mid+1,r); link(v,ls[v]);link(v,rs[v]);}void add(int v,int l,int r,int x,int y,int p){ if(x>y || l>r) return; if(l==x && r==y) { link(p,v); return; } int mid=l+r>>1; if(y<=mid) add(ls[v],l,mid,x,y,p); else if(x>mid) add(rs[v],mid+1,r,x,y,p); else add(ls[v],l,mid,x,mid,p),add(rs[v],mid+1,r,mid+1,y,p);}int now,top,num,low[N],dfn[N],scc[N],sta[N];bool bz[N],vis[N];void tarjan(int v){ low[v]=dfn[v]=++now; bz[v]=vis[v]=1; sta[++top]=v; efo(i,v,u) if(!vis[u]) { tarjan(u); low[v]=min(low[v],low[u]); } else if(bz[u]) low[v]=min(low[v],dfn[u]); if(low[v]==dfn[v]) { sta[top+1]=0;++num; for(;sta[top+1]!=v;top--) bz[sta[top]]=0,scc[sta[top]]=num; }}bool check(int lim){ m=0;mset(last,0); fo(i,1,n) { link(b[i+i-1][0],b[i+i][1]),link(b[i+i][1],b[i+i-1][0]); link(b[i+i-1][1],b[i+i][0]),link(b[i+i][0],b[i+i-1][1]); } tot=vtot; build(root,1,nn); int l=1,r=1; fo(i,1,nn) { while(l<nn && a[i].x-a[l].x>=lim) ++l; while(r<nn && a[r+1].x-a[i].x<lim) ++r; add(root,1,nn,l,i-1,b[a[i].id][1]); add(root,1,nn,i+1,r,b[a[i].id][1]); } now=top=num=0;mset(bz,0);mset(vis,0);mset(scc,0); fo(i,1,vtot) if(!vis[i]) tarjan(i); fo(i,1,nn) if(scc[b[i][0]]==scc[b[i][1]]) return 0; return 1;}int main(){ freopen("a.in","r",stdin); freopen("a.out","w",stdout); int x,y; read(n);nn=n+n; fo(i,1,n) read(a[i+i-1].x),read(a[i+i].x); vtot=1; fo(i,1,nn) a[i].id=i,b[i][0]=++vtot,b[i][1]=++vtot; sort(a+1,a+nn+1,cmp); int l=0,r=a[nn].x+1; while(l<r-1) { int mid=l+r>>1; if(check(mid)) l=mid; else r=mid; } printf("%d\n",l); return 0;}
- 【2-SAT】【AtCoder Regular Contest 069 F】Flag
- AtCoder Regular Contest 069 F
- AtCoder Regular Contest 071 F
- AtCoder Regular Contest 076 F
- AtCoder Regular Contest 071 F
- AtCoder Regular Contest 074 F Lotus Leaves
- AtCoder Regular Contest 082-F-Sandglass
- Atcoder Regular Contest 066 F genocide【JZOJ5451】
- 【Atcoder Regular Contest 085F】 NRE
- AtCoder Regular Contest 069 D
- AtCoder Regular Contest 085 F NRE 线段树优化dp
- Atcoder Regular contest 085F NRE 线段树+DP
- AtCoder Regular Contest 077
- AtCoder Regular Contest 077
- AtCoder Regular Contest 078
- AtCoder Regular Contest 079
- Atcoder Regular Contest 084
- AtCoder Regular Contest 086
- 时间复杂性求解
- 奇异值分解(SVD)原理详解及推导
- HDU 5936 Difference 折半枚举,暴力
- 关于mvp
- 世界名画陈列馆问题-重复&不重复两种
- 【2-SAT】【AtCoder Regular Contest 069 F】Flag
- Android中Json数据格式的解析
- Controller for AR.Drone
- An error occurred while collecting items to be installed session context was
- SEO网络优化是什么工作
- tensorflow的一些基本函数
- 日常学习——区间覆盖
- tensorflow 多分类
- JavaWeb之Cookie中保存中文(URL地址重写)