码迷,mamicode.com
首页 > 其他好文 > 详细

【CF1215F】 Radio Stations

时间:2019-09-22 19:51:57      阅读:95      评论:0      收藏:0      [点我收藏+]

标签:题目   def   mit   www   reg   printf   text   splay   lin   

题目

比较精妙的\(\text{2-sat}\)建图了

还是按照套路把每个电台拆成\((0/1,i)\)表示不选/选

前两种连边是板子就不解释了

考虑如何限制选择一个唯一的\(f\),并且还能限制不选\(f\notin [l_i,r_i]\)的电台

考虑前缀优化建图,我们建\((0/1,i)\)表示在\([0,i]\)中不选/选某一个频率

对于这\(2\times m\)个点有一些显然的连边

\[(1,i)->(1,i+1)\]

\([0,i]\)内启用一个频率则\([0,i+1]\)中必启用一个频率

\[(0,i+1)->(0,i)\]

\([0,i+1]\)没有启用任何一个频率则\([0,i]\)必不会启用任何一个频率

注意到我们必须启用一个频率,所以连\((0,m)->(1,m)\),这样能强制使得\(m\)的拓扑序更靠后

之后对于一个电台\(i\),我们用\([0,l_i-1]\)\([0,r_i]\)这两个前缀的关系来讨论一下

\([0,l_i-1]\)内选择了一个频率时,电台\(i\)就没有办法被启用了,于是连\((1,l_i-1)->(0,i)\),以及对称边\((1,i)->(0,l_i-1)\)

\([0,r_i]\)中没有任何一个频率被启用时,电台\(i\)也没有办法被启用,于是连\((0,r_i)->(0,i)\),以及对称边\((1,i)->(1,r_i)\)

根据我们连得两条对称边,我们发现当启用电台\(i\)的时候能推出\([0,l_i-1]\)没有频率被启用,\([0,r_i]\)有一个频率被启用,即被启用的频率在\([l_i,r_i]\)内,这符合题目要求

代码

#include<bits/stdc++.h>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read() {
    char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
const int maxn=2e6+1;
struct E{int v,nxt;}e[maxn*10];
int dfn[maxn],low[maxn],st[maxn],f[maxn],col[maxn],head[maxn],id[2][maxn>>1],l[maxn>>2],r[maxn>>2];
int n,m,A,B,num,__,cnt,top,col_num,ans,Ans[500005];
inline void add(int x,int y) {e[++num].v=y;e[num].nxt=head[x];head[x]=num;}
void tarjan(int x) {
    dfn[x]=low[x]=++__,st[++top]=x,f[x]=1;
    for(re int i=head[x];i;i=e[i].nxt) 
    if(!dfn[e[i].v]) tarjan(e[i].v),low[x]=min(low[x],low[e[i].v]);
    else if(f[e[i].v]) low[x]=min(low[x],dfn[e[i].v]);
    if(dfn[x]==low[x]) {
        col_num++;int now;
        do{now=st[top--];f[now]=0;col[now]=col_num;}while(x!=now);
    }
}
int main() {
    A=read(),n=read(),m=read(),B=read();
    for(re int i=1;i<=n;i++) id[0][i]=++cnt,id[1][i]=++cnt;
    for(re int i=0;i<=m;i++) id[0][i+1+n]=++cnt,id[1][i+1+n]=++cnt;
    for(re int x,y,i=1;i<=A;i++) {
        x=read(),y=read();
        add(id[0][x],id[1][y]);
        add(id[0][y],id[1][x]);
    }
    for(re int i=1;i<=n;i++) l[i]=read(),r[i]=read();
    for(re int x,y,i=1;i<=B;i++) {
        x=read(),y=read();
        add(id[1][x],id[0][y]);
        add(id[1][y],id[0][x]);
    }
    add(id[1][n+1],id[0][n+1]);
    for(re int i=1;i<=m;i++) {
        int x=i+1+n;
        add(id[0][x],id[0][x-1]);
        add(id[1][x-1],id[1][x]);
    }
    add(id[0][n+m+1],id[1][n+m+1]);
    for(re int i=1;i<=n;i++) {
        int li=l[i]+n,ri=r[i]+n+1;
        add(id[1][li],id[0][i]);
        add(id[1][i],id[0][li]);
        add(id[0][ri],id[0][i]);
        add(id[1][i],id[1][ri]);
    }
    for(re int i=1;i<=cnt;++i) if(!dfn[i]) tarjan(i);
    for(re int i=1;i<=n+1+m;i++) if(col[id[0][i]]==col[id[1][i]]) {puts("-1");return 0;}
    for(re int i=1;i<=n;i++) 
        if(col[id[1][i]]<col[id[0][i]]) Ans[++ans]=i;
    for(re int i=1;i<=m;i++) if(col[id[1][i+n+1]]<col[id[0][i+n+1]]) {
        printf("%d %d\n",ans,i);
        for(re int j=1;j<=ans;j++) printf("%d ",Ans[j]);
        return 0;
    }
}

【CF1215F】 Radio Stations

标签:题目   def   mit   www   reg   printf   text   splay   lin   

原文地址:https://www.cnblogs.com/asuldb/p/11568689.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!