这道题如果没有功率的限制,显然就是一个裸的2-sat
考虑将功率的限制也放在图上:如果选择了功率i,那么功率区间不包含它的点只能不选,连边即可
但是这样建图的边数是o(n^2),需要优化
将功率区间分为两种,一种在这个点前面,另一种在这个点的后面
同样将功率也裂成两个点,分别连向这两种区间,因为功率i的第1种点一定是功率i+1的第一种点的子集,因此(i+1)1->i1和功率右区间恰好在i+1的点,同理(i-1)2->i2和功率左区间恰好为i-1的点
对图求强连通,如果裂成的两个点中在同一个强连通就不行,否则所有选1的区间都要选,功率是最大的i2
1 #include2 using namespace std; 3 #define N 1600005 4 struct ji{ 5 int nex,to; 6 }edge[N<<2]; 7 int E,n,m,m1,m2,x,y,ans,head[N],vis[N],dfn[N],low[N],s[N]; 8 void add(int x,int y){ 9 edge[E].nex=head[x]; 10 edge[E].to=y; 11 head[x]=E++; 12 } 13 void dfs(int k){ 14 dfn[k]=low[k]=++x; 15 s[++s[0]]=k; 16 for(int i=head[k];i!=-1;i=edge[i].nex){ 17 int v=edge[i].to; 18 if (!dfn[v]){ 19 dfs(v); 20 low[k]=min(low[k],low[v]); 21 } 22 else 23 if (!vis[v])low[k]=min(low[k],dfn[v]); 24 } 25 if (dfn[k]==low[k]){ 26 vis[k]=++vis[0]; 27 while (s[s[0]]!=k)vis[s[s[0]--]]=vis[0]; 28 s[0]--; 29 } 30 } 31 int main(){ 32 scanf("%d%d%d%d",&m1,&n,&m,&m2); 33 memset(head,-1,sizeof(head)); 34 for(int i=1;i<=m1;i++){ 35 scanf("%d%d",&x,&y); 36 add(2*x-1,2*y); 37 add(2*y-1,2*x); 38 } 39 for(int i=1;i<=n;i++){ 40 scanf("%d%d",&x,&y); 41 add(2*i,2*n+2*x); 42 add(2*n+2*x-1,2*i-1); 43 if (y<m){ 44 add(2*i,2*n+2*y+1); 45 add(2*n+2*y+2,2*i-1); 46 } 47 } 48 for(int i=1;i<=m2;i++){ 49 scanf("%d%d",&x,&y); 50 add(2*x,2*y-1); 51 add(2*y,2*x-1); 52 } 53 for(int i=1;i ){ 54 add(2*n+2*i+2,2*n+2*i); 55 add(2*n+2*i-1,2*n+2*i+1); 56 } 57 x=0; 58 for(int i=2;i<=2*(n+m);i+=2) 59 if (!dfn[i])dfs(i); 60 for(int i=1;i<=2*(n+m);i+=2) 61 if (!dfn[i])dfs(i); 62 for(int i=1;i<=n+m;i++) 63 if (vis[2*i-1]==vis[2*i]){ 64 printf("-1"); 65 return 0; 66 } 67 for(int i=1;i<=n;i++)ans+=(vis[2*i] 2*i-1]); 68 for(int i=m;i;i--) 69 if (vis[2*n+2*i] 2*n+2*i-1]){ 70 printf("%d %d\n",ans,i); 71 for(int j=1;j<=n;j++) 72 if (vis[2*j] 2*j-1])printf("%d ",j); 73 return 0; 74 } 75 }