Codeforces Round #585 (Div. 2)F. Radio Stations(2-SAT)

                                                        F. Radio Stations

题意:

         输入n,p,M,m(都是2-4e5),

         n表示由n个条件,每个条件输入x,y(1<=x<y<=p)表示x,y中至少选择一个;

         p表示有p个,p行,输入li,ri表示第i个发射塔的功率在li到ri.M表示(1<=li<=ri<=M)

         m表示有m个条件,每个条件输入u,v(1<=u<v<=p)表示u,v不能同时选择。

         问选择哪几个发射塔和什么功率可以满足以上条件。

题解:

          很明显如果没有限制l[i],r[i],就是一道2-SAT板题了,但是加了限制条件,那就稍稍修改一下2-SAT模板就好。

  •   2-SAT套路:i表是选择i,i+p表示不选i(1<=i<=p)。
  •   增加条件:2*p+i表示(>=i),2*p+M+i表示(<=i)(1<=i<=M)于是便可加2*p+i+1->2*p+i和2*p+M+i->2*p+M+i+1(1<=i<M)(这算是初始化加边吧),接下来才是重点,对于li,ri(1<=i<=p) 对于i加边 i->2*p+li,i->2*p+M+ri,对于i+p加边,(ri<M)2*p+ri+1->i+p,(li>1)2*p+M+li-1->i+p;于是边就建好了。

再写一下2-SAT套路吧,按套路建边,然后跑tarjan,选择tarjan跑出反拓扑序小的就好。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=2e6+9;
int n,p,M,m,l[N],r[N];
struct Edge{int v,nxt;}e[N<<2];
int head[N],cnt;
inline void add(int u,int v){e[cnt]=(Edge){v,head[u]},head[u]=cnt++;}
int dfn[N],low[N],num,co[N],col;
stack<int>S;bool vis[N];
void tarjan(int u){
    dfn[u]=low[u]=++num;
    S.push(u),vis[u]=1;
    for(int i=head[u],v;~i;i=e[i].nxt){
        v=e[i].v;
        if(!dfn[v])tarjan(v),low[u]=min(low[u],low[v]);
        else if(vis[v])low[u]=min(low[u],dfn[v]);
    }
    if(dfn[u]==low[u]){
        co[u]=++col;vis[u]=0;
        while(S.top()!=u){
            co[S.top()]=col;vis[S.top()]=0;
            S.pop();
        }
        S.pop();
    }
}
int main(){
   // freopen("tt.in","r",stdin),freopen("tt.out","w",stdout);
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin>>n>>p>>M>>m;
    memset(head,-1,sizeof(head));
    for(int i=1,x,y;i<=n;i++)cin>>x>>y,add(x+p,y),add(y+p,x);
    for(int i=1;i<M;i++)add(2*p+i+1,2*p+i),add(2*p+M+i,2*p+M+i+1);
    for(int i=1;i<=p;i++){
        cin>>l[i]>>r[i];
        add(i,2*p+l[i]),add(i,2*p+M+r[i]);
        if(r[i]<M)add(2*p+r[i]+1,i+p);
        if(l[i]>1)add(2*p+M+l[i]-1,i+p);
    }
    for(int i=1,u,v;i<=m;i++)cin>>u>>v,add(u,v+p),add(v,u+p);//cout<<u<<" "<<v<<endl;
    for(int i=1;i<=2*p+2*M;i++)if(!dfn[i])tarjan(i);
    for(int i=1;i<=p;i++)if(co[i]==co[i+p]){cout<<-1<<endl;return 0;}
    vector<int>ans;int lim=0;
    for(int i=1;i<=p;i++)if(co[i]<co[i+p])ans.push_back(i),lim=max(lim,l[i]);
    cout<<ans.size()<<" "<<lim<<endl;
    for(auto i:ans)cout<<i<<" ";cout<<endl;
    return 0;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值