• 【CF1215F】 Radio Stations


    题目

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

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

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

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

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

    对于这(2 imes 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
    ",ans,i);
    		for(re int j=1;j<=ans;j++) printf("%d ",Ans[j]);
    		return 0;
    	}
    }
    
  • 相关阅读:
    从程序员到项目经理(14):项目管理三大目标
    从程序员到项目经理(13):项目经理必须懂一点“章法”
    从程序员到项目经理(12):如何管理自己的时间(下)
    从程序员到项目经理(11):如何管理自己的时间(上)
    从程序员到项目经理(10):每个人都是管理者
    从程序员到项目经理(9):程序员加油站 --要执着但不要固执
    从程序员到项目经理(8):程序员加油站 -- 再牛也要合群
    从程序员到项目经理(6):程序员加油站 -- 完美主义也是一种错
    从程序员到项目经理(7):程序员加油站 -- 不要死于直率
    [SQL]不知道
  • 原文地址:https://www.cnblogs.com/asuldb/p/11568689.html
Copyright © 2020-2023  润新知