[2017纪中11-3][ARC069-F]高考是不可能高考的 2-sat+线段树优化建图
2017-11-03 21:04
316 查看
题面
原题
首先考虑二分答案k,验证就可以用2-sat。假如要选某一个x[i],那么x[i]左右距离k的区间内的点都不能选,于是这些点都必须选另一半;y[i]同理。
由于边数太多,直接建图是不可接受的,考虑到不能选的点都在一个区间内,于是把所有x[i],y[i]排序,开一棵线段树,x的位置存y的点编号,y的位置存x的点编号(因为要连另一半嘛),建边时向线段树上节点连,线段树从根往叶子连边,边数控制在nlogn级别。
注意因为自己也在自己不可选的区间内,导致自己向自己的另一半连边,预处理另一半的位置,以这个位置把原来区间分成左右两半即可。
代码:
原题
首先考虑二分答案k,验证就可以用2-sat。假如要选某一个x[i],那么x[i]左右距离k的区间内的点都不能选,于是这些点都必须选另一半;y[i]同理。
由于边数太多,直接建图是不可接受的,考虑到不能选的点都在一个区间内,于是把所有x[i],y[i]排序,开一棵线段树,x的位置存y的点编号,y的位置存x的点编号(因为要连另一半嘛),建边时向线段树上节点连,线段树从根往叶子连边,边数控制在nlogn级别。
注意因为自己也在自己不可选的区间内,导致自己向自己的另一半连边,预处理另一半的位置,以这个位置把原来区间分成左右两半即可。
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=10010; const int maxd=40010; int n,num,tim,top,nc,rx[maxn],ry[maxn],g[maxn<<1],dfn[maxd],low[maxd],col[maxd],st[maxd]; bool vis[maxd],vst[maxd]; struct edge { int t; edge *next; }*con[maxd]; struct node { int d,b; bool operator <(const node &x) const{return d<x.d;} }e[maxn<<1]; void ins(int x,int y) { if(y==0||x==y) return; edge *p=new edge; p->t=y; p->next=con[x]; con[x]=p; } struct tree { int l,r,id; tree *ls,*rs; tree() { ls=rs=NULL; l=r=id=0; } void update() { id=++num; ins(id,ls->id); ins(id,rs->id); } void build(int lx,int rx) { l=lx;r=rx; if(l==r) { if(e[l].b>n) id=e[l].b-n; else id=e[l].b+n; g[e[l].b]=l; return ; } int mid=(l+r)>>1; (ls=new tree)->build(lx,mid); (rs=new tree)->build(mid+1,rx); update(); } void ade(int bg,int lx,int rx) { if(lx>rx) return; if(l==lx&&r==rx) {ins(bg,id); return;} int mid=(l+r)>>1; if(rx<=mid) ls->ade(bg,lx,rx); else if(lx>mid) rs->ade(bg,lx,rx); else ls->ade(bg,lx,mid),rs->ade(bg,mid+1,rx); } }*xtr; void tarjan(int v) { vis[v]=vst[v]=1; low[v]=dfn[v]=++tim; st[++top]=v; for(edge *p=con[v];p;p=p->next) if(!vis[p->t]) tarjan(p->t),low[v]=min(low[v],low[p->t]); else if(vst[p->t]) low[v]=min(low[v],dfn[p->t]); if(low[v]==dfn[v]) { nc++; while(st[top+1]!=v) {vst[st[top]]=0;col[st[top--]]=nc;} } } bool check(int v) { for(int i=1;i<=2*n;i++) con[i]=NULL; for(int i=1;i<=n;i++) { int Lx,Rx,Ly,Ry; Lx=lower_bound(e+1,e+2*n+1,(node){rx[i]-v+1,0})-e; Rx=upper_bound(e+1,e+2*n+1,(node){rx[i]+v-1,0})-e-1; Ly=lower_bound(e+1,e+2*n+1,(node){ry[i]-v+1,0})-e; Ry=upper_bound(e+1,e+2*n+1,(node){ry[i]+v-1,0})-e-1; if(Lx<=Rx)xtr->ade(i,Lx,g[i]-1),xtr->ade(i,g[i]+1,Rx); if(Ly<=Ry)xtr->ade(i+n,Ly,g[i+n]-1),xtr->ade(i+n,g[i+n]+1,Ry); } memset(vis,0,sizeof(vis)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(col,0,sizeof(col)); tim=top=nc=0; for(int i=1;i<=num;i++) if(!vis[i]) tarjan(i); for(int i=1;i<=n;i++) if(col[i]==col[i+n]) return 0; return 1; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d%d",&rx[i],&ry[i]); e[2*i-1].d=rx[i];e[2*i-1].b=i; e[2*i].d=ry[i];e[2*i].b=i+n; } sort(e+1,e+2*n+1); num=2*n; (xtr=new tree)->build(1,2*n); int L=0,R; if(n<=1000) R=1e9; else R=28000; while(L<R) { int mid=(L+R)>>1; if(check(mid)) L=mid+1; else R=mid; } printf("%d",L-1); return 0; }
相关文章推荐
- [JZOJ5446]【NOIP2017提高A组冲刺11.3】高考是不可能高考的(2-SAT问题)【Atcoder regular context 069F】
- 【项目经理之修炼(11)】《初级篇》什么样的项目经理才可能成功??
- [2017纪中11-2]字典序 拓扑排序+优先队列
- 你可能需要为你的 APP 适配 iOS 11
- [2017纪中11-8]购物 贪心+优先队列
- 一道题:给定一整数序列A1,A2,...,An(可能有负数),求A1到An的一个自序列,使得Ai到Aj的和最大。例如:整数序列-2,11,-4,13,-5,2,-5,-3,12,-9的最大子序列为21
- 项目经理之修炼(11)——什么样的项目经理才可能成功?
- [2017纪中11-8]好文章 字符串hash+STL
- [2017纪中11-2]救赎 dfs序+树状数组 / 递推
- [2017纪中11-4][Codeforces Round #395 Div.1]C pacifist
- [2017纪中11-9]乘积 数论+分组背包
- [2017纪中11-2]失格 最小生成树+数论
- [2017纪中11-9]道路重建 点双连通分量+树的直径
- UVa 10929 You can say 11 (......可能算数论)
- [2017纪中11-4][ARC071]F-neutral DP
- [2017纪中11-9]玩游戏 最短路数+LCA 4000
- csdn可能待改进点之11------>建议支持直接在博文中贴入图片, 而不需要上传、插入这么麻烦
- 【项目经理之修炼(11)】《初级篇》什么样的项目经理才可能成功??(转)
- [2017纪中11-1]背包 二分
- [2017纪中11-5]轰炸 强联通分量+DAG最长路