题意
有n个正整数X1,X2,...,Xn,再给出m1+m2个限制条件,限制分为两类:
1. 给出a,b (1<=a,b<=n),要求满足Xa + 1 = Xb
2. 给出c,d (1<=c,d<=n),要求满足Xc <= Xd
在满足所有限制的条件下,求集合{Xi}大小的最大值。
(自己注:求集合中不相同的的元素最多)
solution
(最后发现我tarjan写挂了......)
1.建图
Xa+1==Xb -> Xa+1<=Xb && Xa+1>=Xb
Xc<=Xd -> Xc-Xd<=0
2.floyd判负环(无解)&&求出两点之间的最短距离
初始化mp[i][j]为INF
记录下边后,把mp[i][j]=0
floyd一遍,如果mp[i][i]<0,说明存在负环 (因为自己到自己不是0,肯定是走了一个负环回来,变小了,一定有负环嘛)
3.tarjan缩点
最后的ans是所有强联通分量 max-min+1 的和
证明:
对于每一个强连通分量,把他们连起来的一定是 w=0 的边
如果不是,一定是{1,-1},但是两个点之间的边是相反关系,如果有1/-1边连强连通分量,那么一定有一条-1/1的边
就不是两个强连通分量了
而又因为边只有{0,1,-1}的边,所以从最小值~最大值一定是连续的,min又一定是0,因为有1/-1的边
所以ans=∑(max-min+1)
对于每一个强连通分量,求出最短路的最大值+1,即为此强连通分量对ans的贡献
累加起来即可
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #define mem(a,b) memset(a,b,sizeof(a)) 5 using namespace std; 6 const int N=606; 7 struct son 8 { 9 int v,next; 10 }; 11 son a1[200066]; 12 int first[200066],e; 13 void addbian(int u,int v) 14 { 15 a1[e].v=v; 16 a1[e].next=first[u]; 17 first[u]=e++; 18 } 19 20 int n,m1,m2; 21 int u,o; 22 int mp[N][N]; 23 int dfn[N],low[N],now,ans; 24 int zhan[200006],he,flag[N]; 25 int ji[N],jinow; 26 27 void jilu() 28 { 29 int temp=-0x7fffffff; 30 for(int i=1;i<=jinow;++i) 31 for(int j=1;j<=jinow;++j) 32 { 33 if(mp[ji[i]][ji[j]]>temp) 34 temp=mp[ji[i]][ji[j]]; 35 } 36 ans+=temp+1; 37 } 38 39 void tarjan(int x) 40 { 41 //printf("x=%d\n",x); 42 low[x]=dfn[x]=++now; 43 flag[x]=1;zhan[++he]=x; 44 for(int i=first[x];i!=-1;i=a1[i].next) 45 { 46 int temp=a1[i].v; 47 //cout<<temp; 48 if(dfn[temp]==-1) 49 { 50 tarjan(temp); 51 if(low[x]>low[temp]) 52 low[x]=low[temp]; 53 } 54 else 55 if(flag[temp]) 56 if(low[x]>dfn[temp]) 57 low[x]=dfn[temp]; 58 } 59 60 if(low[x]==dfn[x]) 61 { 62 int temp; 63 jinow=0; 64 while(1) 65 { 66 temp=zhan[he--];flag[temp]=0; 67 ji[++jinow]=temp; 68 if(temp==x) 69 break; 70 } 71 jilu(); 72 } 73 } 74 75 int floyd() 76 { 77 int temp; 78 for(int i=1;i<=n;++i) 79 mp[i][i]=0; 80 for(int k=1;k<=n;++k) 81 for(int i=1;i<=n;++i) 82 for(int j=1;j<=n;++j) 83 { 84 temp=mp[i][k]+mp[k][j]; 85 if(mp[i][j]>temp) 86 mp[i][j]=temp; 87 } 88 for(int i=1;i<=n;++i) 89 if(mp[i][i]<0) 90 return 0; 91 return 1; 92 } 93 94 int main(){ 95 96 //freopen("1.txt","r",stdin); 97 98 mem(first,-1); 99 mem(mp,0x3f); 100 mem(dfn,-1); 101 102 scanf("%d%d%d",&n,&m1,&m2); 103 for(int i=1;i<=m1;++i) 104 { 105 scanf("%d%d",&u,&o); 106 addbian(u,o); 107 addbian(o,u); 108 mp[u][o]=min(1,mp[u][o]); 109 mp[o][u]=min(-1,mp[o][u]);//有可能会重复 110 } 111 for(int i=1;i<=m2;++i) 112 { 113 scanf("%d%d",&u,&o); 114 addbian(o,u); 115 mp[o][u]=min(0,mp[o][u]); 116 } 117 if(floyd()==0) 118 { 119 printf("NIE\n"); 120 return 0; 121 } 122 // cout<<0; 123 for(int i=1;i<=n;++i) 124 if(dfn[i]==-1) 125 tarjan(i); 126 127 cout<<ans<<endl; 128 //while(1); 129 return 0; 130 }
code
时间: 2024-10-01 04:32:05