2024icpc上海E题题解及感想
2024icpc上海E题题解
在这场icpc区域赛之前,我们队已经打了icpc南京和ccpc重庆,分别拿了银牌和铜牌。这场其实是非常希望可以拿金牌的,但是E题最后还是没能做出来,所以还是拿了一块银牌。
不过赛后拿到补题链接后用赛时思路写了一遍,发现赛时的思路假了。
但是后来转念一想,为什么我要写在线形式的,写离线形式会简单很多,然后经过20多发的debug成功赛后AC。
我的思路应该和其他人不太一样,因为听说其他人有用到缩点,但是我这个不需要:
首先对于这个图跑dfs,这样可以得到一个生成树,剩下的没有用到的边就肯定会形成至少一个环。
我们假设没有用到的边的两个端点为u和v,那么u到v之间的链,根据dfs生成树的性质,很显然u和v的链是直通根节点的(u直通根节点的链与v直通根节点的链是包含关系)
利用这个性质可以少讨论很多东西。
然后,通过写写画画,我们发现,只要除去一种特殊情况,一个环上最多只能连一个环。
这里给出特殊情况,假定有两个环,其公共部分的链的两个端点为l和r,如果有其他环与这两个环的公共部分同样是这条链,那么是可行的,其他情况均不可以。
首先两个环如果有公共部分,那么这个公共部分的长度必须满足是环的长度的一半加一。
这里给出一个证明:假定有三个环,保证这三个环的长度都是相等的(>=3),先考虑其中两个环的公共部分刚好是环的长度的一半+1,这样这两个环是合法相连,记公共部分的两个端点为l和r。假设第三个环和第一个环的公共部分为L和R(L!=l,R!=r),并且也保证这部分链的长度为环的长度的一半+1,很容易发现第一个环和第二个环一定会相交,并且由于L!=l,R!=r,这两个环之间的公共部分的链的长度一定是小于等于环的长度的一半+1。
那么这里已经给出了这个图的性质,接下来是实现的思路。
我们只需要dfs的时候记一下成环的边的两个端点,每次遍历完一个子树之后,对于经过该端点的环进行处理即可。(这里把经过定义成环的节点中要包括该端点的父亲节点),同时经过该端点的环其实是不超过三个的,因为上述的特殊情况的所有环可以视作两个环(本来是可以视作一个环的,但是要考虑到向下兼容),那么很显然的,其实是可以暴力存储每个端点上的环,然后暴力对这些环进行处理的(处理就是考虑两个环之间的公共部分长度是否满足条件)。
记得把符合条件的环传给父亲节点。
虽然时间复杂度应该是O(nlogn)但是常数感觉很小。
这里给出代码实现。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl "\n"
const int N=5e5+10;
int n,m;
int dep[N];
struct line{
int l,r;
};
bool vis[N];
bool flag=true;
int ans=-1;
void dfs(int x,int back,vector<vector<int>>& q,vector<vector<line>>& st,map<pair<int,int>,int>& p){
dep[x]=dep[back]+1;
vis[x]=true;
if(!flag) return;
for(auto& it:q[x]){
if(it==back) continue;
if(vis[it]){
if(dep[it]>dep[x]) continue;
if(ans==-1) ans=dep[x]-dep[it]+1;
else if(ans!=dep[x]-dep[it]+1){
flag=false;
return;
}
st[x].push_back({x,it});
continue;
}
dfs(it,x,q,st,p);
if(!flag) return;
}
if(!flag) return;
for(auto& i:st[x]){
for(auto& j:st[x]){
if(p[{i.l,j.l}]) continue;
p[{i.l,j.l}]=x;
}
}
for(auto& it:st[x]){
if(it.r!=back) {
int num=0;
for(auto& ppp:st[back]){
if(ppp.r==it.r&&dep[ppp.l]==dep[it.l]&&dep[back]-dep[ppp.r]==ans/2&&ans%2==0) ++num;
}
if(num<2) st[back].push_back({it.l,it.r});
}
}
for(int i=0;i<st[x].size();i++){
for(int j=i+1;j<st[x].size();j++){
auto& L=st[x][i],R=st[x][j];
int res=dep[p[{L.l,R.l}]]-max(dep[L.r],dep[R.r]);
if(res!=ans/2||ans%2==1){
flag=false;
return;
}
}
}
}
void solve(){
cin>>n>>m;ans=-1;
map<pair<int,int>,int> p,pp;
vector<vector<int>> q(n+4);
vector<vector<line>> st(n+4);
for(int i=0;i<=n;i++) vis[i]=false;
for(int i=1;i<=m;i++){
int l,r;cin>>l>>r;
q[l].push_back(r);
q[r].push_back(l);
}
flag=true;
dfs(1,0,q,st,p);
if(flag) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
signed main(){
std::ios::sync_with_stdio(false);
cin.tie(nullptr);
int __T=1;cin>>__T;
while(__T--) solve();
}
浙公网安备 33010602011771号