题目大意:有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 }