cf 1215F Radio Stations

题目链接

 

题目大意:有n个地方需要通讯,每个地方可以用两种基站里面的其中一种,有p种基站, 每种基站能够接收的频率在l到r范围内,最大的频率是M,有m对基站会相互干扰,所以不能同时选。 

要求一种频率,使得每个地方都能通讯。  输出使用的频率和哪几个基站。  

 

题目分析: 这题明显可以用2sat来做,但是我们知道只有在确定频率的基础上我们才可以建图。 所以最朴素的做法就是枚举各种频率,然后每次建图判断,这样做的时间复杂度比较高。 

这题有一个巧妙的方法,我们可以把频率也看成一个点,这样就不用重复建图了。  比如第i个点的两个对立面,频率大于等于i和频率小于i。 那么我们可以这么建图: 

频率小于i可以推出频率小于i+1

频率大于等于i+1,可以推出频率大于等于i

 

某个基站的频率范围是l到r,那么我们可以建边。 

频率小于l推出这个基站不选

这个基站选了可以推出频率大于等于l

 

频率大于等于r+1可以推出这个基站不选

这个基站选了可以推出频率小于r+1。  

 

再加上本身2sat的建图,边的数量大概在400万左右,可以承受。 

 

最后找答案,也就是频率,也有一定的技巧。 

我们需要先计算出哪些小于i的频率选了。 

因为我们知道频率小于i,可以推出频率小于i+1,也可以推出频率小于i+2,。。。。 所以肯定有一段连续的频率小于某些值的被选了。 

所以我们可以倒着枚举,因为频率小于M+1是一定选了的。  

时间复杂度是线性的。  

 1 #include<bits/stdc++.h>
 2 using namespace std; 
 3 int const N=400000+10;  
 4 int const M=1600000+10;  
 5 int h[M],cnt,bl[M],dfn[M],low[M],sum,n,p,t,s[M],top,vis[M],m;  
 6 struct edge{
 7     int to,nt;  
 8 }e[M<<2]; 
 9 void add(int a,int b){ 
10     e[++cnt].to=b;  
11     e[cnt].nt=h[a];  
12     h[a]=cnt;   
13 }
14 void dfs(int x){
15     dfn[x]=low[x]=++cnt;  
16     s[++top]=x;  
17     for(int i=h[x];i;i=e[i].nt){
18         int v=e[i].to;  
19         if(!dfn[v]){
20             dfs(v);  
21             low[x]=min(low[x],low[v]);  
22         }else if(!bl[v])  low[x]=min(low[x],dfn[v]);  
23     }
24     if(dfn[x]==low[x]){
25         sum++; 
26         while (s[top]!=x){
27             bl[s[top]]=sum;  
28             top--;  
29         }
30         bl[x]=sum; top--;   
31     }
32 }
33 int main(){ 
34     scanf("%d%d%d%d",&n,&p,&m,&t);  
35     for(int i=1;i<=n;i++){
36         int x,y;  
37         scanf("%d%d",&x,&y);  
38         add(x<<1,y<<1|1);  
39         add(y<<1,x<<1|1);  
40     }
41     for(int i=1;i<=m;i++){
42         add((p+i)<<1|1,(p+i+1)<<1|1);  
43         add((p+i+1)<<1,(p+i)<<1);  
44     }
45     for(int i=1;i<=p;i++){
46         int x,y;  
47         scanf("%d%d",&x,&y);  
48         add((p+x)<<1|1,i<<1); 
49         add(i<<1|1,(p+x)<<1);  
50         add((p+y+1)<<1,i<<1);  
51         add(i<<1|1,(p+y+1)<<1|1);   
52     }
53     for(int i=1;i<=t;i++){
54         int x,y; 
55         scanf("%d%d",&x,&y);  
56         add(x<<1|1,y<<1);  
57         add(y<<1|1,x<<1);   
58     }
59     cnt=0; int ans=0;  
60     for(int i=2;i<=(p+m)*2+3;i++)  
61         if(!bl[i]) dfs(i);   
62     int f=m;     
63     for(int i=1;i<=p+m+1;i++)  
64         if(bl[i<<1]==bl[i<<1|1]) {
65             printf("-1\n");  
66             return 0;  
67         }else{
68             vis[i]=bl[i<<1|1]<bl[i<<1];  
69             if(i<=p) ans+=vis[i];  
70         }
71     while (f>0 && vis[p+f+1])  f--;  
72     printf("%d %d\n",ans,f+1);  
73     for(int i=1;i<=p;i++) 
74         if(vis[i]) printf("%d ",i);  
75     return 0;
76 }
View Code

 

posted @ 2019-09-17 23:36  zjxxcn  阅读(233)  评论(0编辑  收藏  举报