Session in BSU
有n场考试,每场考试有两个参加的时间点,求参加完所有的考试的最早时间
把每个时间点看成点,每场考试的两个点相连,那么边就代表每场考试,考试的场数为边数en,参加考试的时间点为顶点数量vn
对于每个连通板块,只有三种情况
vn==en,那么刚好一个时间点参加一场考试,因此参加完所有考试的时间是此板块中所有时间点的最大值,这种情况下板块中肯定存在环
vn=en+1,有一个多余的时间点,则肯定不选最晚的时间点,即最大值,所以答案是次大值,这种情况下板块是树
vn<en,考试场数多于可选时间点,没办法参加所有考试
把每个连通板块的值求出来之后求最大值就是最终结果
使用并查集维护各个点之间关系、vn、en和最大值、次大值
#include<stdio.h>
#include<vector>
#include<algorithm>
#include<string.h>
#include<iostream>
#include<fstream>
#include<math.h>
#include<stack>
#include<queue>
#include<bitset>
#include<utility>
#include<set>
#include<map>
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long ll;
const double eps=0.0000000000001;
const ll mod=998244353;
int n;
int pre[2000010];
bool f[2000010];//判断是否有环
int vn[2000010];//点数
int en[2000010];//边数
int ma[2][2000010];//ma[0]存放最大值,ma[1]存放次大值
map<int,int>id;//存放每个时间点对应id
int find(int x){
int r=x;
while(pre[r]!=r){
r=pre[r];
}
int i=x,j;
while(pre[i]!=r){
j=pre[i];
pre[i]=r;
i=j;
}
return r;
}
void update(int rx,int ry){
//更新连通板块中最大值与次大值
int a=ma[0][rx];
int b=ma[1][rx];
int c=ma[0][ry];
int d=ma[1][ry];
if(b>=c){
ma[0][ry]=a;
ma[1][ry]=b;
}
else if(a>=c&&c>b){
ma[0][ry]=a;
ma[1][ry]=c;
}
else if(c>a&&a>=d){
ma[0][ry]=c;
ma[1][ry]=a;
}
else if(d>a){
ma[0][ry]=c;
ma[1][ry]=d;
}
}
void add(int x,int y){
//加边
int rx=find(x);
int ry=find(y);
en[ry]++;
if(rx!=ry){
pre[rx]=ry;
vn[ry]+=(vn[rx]+1);
en[ry]+=en[rx];
update(rx,ry);
if(f[rx]==1)f[ry]=1;
}
else{
f[ry]=1;//如果x、y已连通,则说明有环
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=2*n;i++){
pre[i]=i;
}
int m=0;
memset(f,0,sizeof(f));
memset(vn,0,sizeof(vn));
memset(en,0,sizeof(en));
int a,b;
int ai,bi;
int k=1;
for(int i=1;i<=n;i++){
scanf("%d%d",&a,&b);
map<int,int>::iterator iter;
iter=id.find(a);
if(iter!=id.end()){
ai=iter->second;
}
else{
id.insert(make_pair(a,k));
ai=k;
ma[0][k]=a;
ma[1][k]=0;
k++;
}
iter=id.find(b);
if(iter!=id.end()){
bi=iter->second;
}
else{
id.insert(make_pair(b,k));
bi=k;
ma[0][k]=b;
ma[1][k]=0;
k++;
}
add(ai,bi);
}
k--;
int ans=0;
bool flag=1;
for(int i=1;i<=k;i++){
if(pre[i]==i){
if(vn[i]+1<en[i]){
flag=0;
break;
}
if(f[i]==1){
ans=max(ans,ma[0][i]);
}
else ans=max(ans,ma[1][i]);
}
}
if(flag==0)printf("-1\n");
else printf("%d\n",ans);
return 0;
}
不知道为什么很喜欢并查集,明明上一题的dp真的想不透超down的,这一题打完ちょうきもじ