题目链接

题目大意:有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
01-15 21:23