CF36E Two Paths
作者:互联网
XXXV.CF36E Two Paths
为什么这题会被归到数据结构博客里呢?因为我的代码使用了大剂量的 STL
。
我吹爆 list
有没有!再也不手写链表了(并不),但是在欧拉路问题上真的贼好用!
首先,覆盖所有边恰一次,妥妥的欧拉路模型。
然后就先考虑如何判无解了。怎样无解呢?
-
有少于 \(2\) 条边。(如果不是样例给了,大概很难注意到……)
-
有超过 \(2\) 个连通块。
-
仅有一个连通块,且连通块中奇点数大于 \(4\)。
-
有两个连通块,且其中某一个块中奇点数大于 \(2\)。
那么,是否所有条件都满足,就一定有解呢?
是的。
假如从欧拉路的方向考虑,就会非常麻烦,因为你找出的欧拉路删去后可能使得这张图分成许多不连通的图。
因此,这里有一个很好的思路:在两个奇点间连边,这样就会转换为欧拉回路,然后在欧拉回路上断去新加的边就行了。
具体而言,对于两个连通块的情形,显然上述结论正确,因为每个连通块都必然符合条件。
然后,对于仅有一个连通块的情形,其中可能有 \(0\) 个,\(2\) 个或是 \(4\) 个奇点。
\(0\) 个奇点就搜出回路然后随便砍两刀断环成链即可。
\(2\) 个奇点就在额外连的那条边处砍一刀,然后再随便砍一刀就行。
\(4\) 个奇点这两刀必须砍在额外的两条边的位置。这形成的两条链必然非空,因为这两条新边必然无公共端点,即其在欧拉环上必然不相邻。
时间复杂度 \(O(m)\)。
致死量 STL
的代码:
#include<bits/stdc++.h>
using namespace std;
int m,n,X[10010],Y[10010],dsu[20010],lim,id[20010];
bool deg[20010],used[10010];
vector<int>v,u[20010],w[20010];
int find(int x){return dsu[x]==x?x:dsu[x]=find(dsu[x]);}
void merge(int x,int y){
x=find(x),y=find(y);
if(x==y)return;
dsu[y]=x;
}
#define lst list<int>::iterator
list<int>ls;
void dfs(lst pos,int x){
while(true){
while(!w[x].empty()&&used[w[x].back()])w[x].pop_back();
if(w[x].empty())return;
int i=w[x].back(),y=X[i]^Y[i]^x;w[x].pop_back(),used[i]=true;
dfs(ls.insert(pos,i),y);
}
}
vector<int>s[3];
int main(){
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
scanf("%d",&m);
for(int i=1;i<=m;i++)scanf("%d%d",&X[i],&Y[i]),v.push_back(X[i]),v.push_back(Y[i]);
if(m==1){puts("-1");return 0;}
sort(v.begin(),v.end()),v.resize(n=unique(v.begin(),v.end())-v.begin());
for(int i=1;i<=n;i++)dsu[i]=i;
for(int i=1;i<=m;i++)merge(X[i]=lower_bound(v.begin(),v.end(),X[i])-v.begin()+1,Y[i]=lower_bound(v.begin(),v.end(),Y[i])-v.begin()+1),deg[X[i]]^=1,deg[Y[i]]^=1;
// for(int i=1;i<=m;i++)printf("%d %d\n",X[i],Y[i]);
// for(int i=1;i<=n;i++)printf("(%d,%d)",find(i),deg[i]);puts("");
for(int i=1;i<=n;i++)if(dsu[i]==i)id[i]=++lim;
for(int i=1;i<=n;i++)u[id[find(i)]].push_back(i);
if(lim>=3){puts("-1");return 0;}
for(int i=1;i<=m;i++)w[X[i]].push_back(i),w[Y[i]].push_back(i);
if(lim==1){
vector<int>sp;
for(auto i:u[1])if(deg[i])sp.push_back(i);
if(sp.size()>4){puts("-1");return 0;}
for(int i=0;i<sp.size();i+=2){
int eid=m+i/2+1;
X[eid]=sp[i],Y[eid]=sp[i+1],w[sp[i]].push_back(eid),w[sp[i+1]].push_back(eid);
}
dfs(ls.begin(),u[1].back());
// printf("%d\n",sp.size());
if(sp.empty()){
s[1].push_back(ls.front()),ls.pop_front();
for(auto i:ls)s[2].push_back(i);
}
if(sp.size()==2){
while(ls.front()<=m)ls.push_back(ls.front()),ls.pop_front();
ls.pop_front();
s[1].push_back(ls.front()),ls.pop_front();
while(!ls.empty())s[2].push_back(ls.front()),ls.pop_front();
}
if(sp.size()==4){
while(ls.front()<=m)ls.push_back(ls.front()),ls.pop_front();
ls.pop_front();
while(ls.front()<=m)s[1].push_back(ls.front()),ls.pop_front();
ls.pop_front();
while(!ls.empty())s[2].push_back(ls.front()),ls.pop_front();
}
}
if(lim==2){
for(int i=1;i<=2;i++){
ls.clear();
vector<int>sp;
for(auto j:u[i])if(deg[j])sp.push_back(j);
if(sp.size()>2){puts("-1");return 0;}
if(!sp.empty())X[m+1]=sp[0],Y[m+1]=sp[1],w[sp[0]].push_back(m+1),w[sp[1]].push_back(m+1),used[m+1]=false;
dfs(ls.begin(),u[i].back());
if(!sp.empty()){while(ls.front()<=m)ls.push_back(ls.front()),ls.pop_front();ls.pop_front();}
while(!ls.empty())s[i].push_back(ls.front()),ls.pop_front();
}
}
for(int i=1;i<=2;i++){
printf("%d\n",s[i].size());
for(auto j:s[i])printf("%d ",j);puts("");
}
return 0;
}
标签:Paths,连通,CF36E,int,sp,Two,奇点,back,return 来源: https://www.cnblogs.com/Troverld/p/14612734.html