CF627F Island Puzzle.

容易观察到一次操作是将 0 移动到一个相邻的节点上,而且操作可逆转。

所以对于不加边的情况方案是唯一的,直接模拟一下看看是不是相等的就好。

对于加一条边来说,我们先将 0 移动到目标位置,观察一下这种状态下他的答案长什么样子。

因为操作是可逆的,所以对于 0 出去再回来的话,他能改变的只有在加一条边形成的环上的点,而改变的方式则是先拿出一个点来,剩下的点转一下,再把拿出来的这个点塞回去。

那么我们可以找到需要改变的这个环,如果需要改变的点形不成一条路径,那么答案为 1

形成环的话我们找到这个环一开始被拿出来的那个点,这个时候路径就确定了,求最优解只需要把和开始时 0 向终点移动时的路径相反的部分减掉就可以了,复杂度 O(n)

代码:

Copy
#include<bits/stdc++.h> #define N 201001 #define MAX 2005 using namespace std; typedef long long ll; typedef double db; const ll inf=1e18,mod=1e9+7; inline void read(ll &ret) { ret=0;char c=getchar();bool pd=false; while(!isdigit(c)){pd|=c=='-';c=getchar();} while(isdigit(c)){ret=(ret<<1)+(ret<<3)+(c&15);c=getchar();} ret=pd?-ret:ret; return; } ll n,a[N],b[N],x,y,pos[N],p,s,t; bool f[N]; vector<ll>v[N]; ll fat[N]; ll dep[N]; inline void dfs(ll ver,ll fa) { fat[ver]=fa; for(int i=0;i<v[ver].size();i++) { ll to=v[ver][i]; if(to==fa) continue; dep[to]=dep[ver]+1; dfs(to,ver); } return; } ll tmp[N]; ll lis[N],tot; inline bool cmp(ll x,ll y) { return dep[x]>dep[y]; } bool vis[N]; ll tp[N]; vector<ll>g; ll h[N],cnt; inline ll calc1() { cnt=0; ll res=0; if(g.size()==1) { ll now=g[0]; while(now!=p) { h[cnt++]=now; if(!f[now]) res++; else res--; now=fat[now]; } res++; h[cnt++]=p; reverse(h,h+cnt); for(int i=0;i<cnt;i++) pos[b[h[i]]]=i; set<ll>dt; for(int i=1;i<cnt;i++) { ll d=0; if(pos[tmp[h[i]]]<i) d=i-pos[tmp[h[i]]]; else d=i+cnt-1-pos[tmp[h[i]]]; dt.insert(d); } if(dt.size()>1) { puts("-1"); exit(0); } ll d=*dt.begin(); return res+(d-1)*cnt; } else { ll now=g[0]; while(now!=p) { h[cnt++]=now; if(!f[now]) res++; else res--; now=fat[now]; } h[cnt++]=p; reverse(h,h+cnt); res++; now=g[1]; while(now!=p) { h[cnt++]=now; res++; now=fat[now]; } for(int i=0;i<cnt;i++) pos[b[h[i]]]=i; set<ll>dt; for(int i=1;i<cnt;i++) { ll d=0; if(pos[tmp[h[i]]]<i) d=i-pos[tmp[h[i]]]; else d=i+cnt-1-pos[tmp[h[i]]]; dt.insert(d); } if(dt.size()>1) { puts("-1"); exit(0); } ll d=*dt.begin(); return res+(d-1)*cnt; } } inline ll calc2() { cnt=0; ll res=0; if(g.size()==1) { ll now=g[0]; h[cnt++]=p; res++; while(now!=p) { h[cnt++]=now; res++; now=fat[now]; } for(int i=0;i<cnt;i++) pos[b[h[i]]]=i; set<ll>dt; for(int i=1;i<cnt;i++) { ll d=0; if(pos[tmp[h[i]]]<i) d=i-pos[tmp[h[i]]]; else d=i+cnt-1-pos[tmp[h[i]]]; dt.insert(d); } if(dt.size()>1) { puts("-1"); exit(0); } ll d=*dt.begin(); return res+(d-1)*cnt; } else { ll now=g[1]; while(now!=p) { h[cnt++]=now; if(!f[now]) res++; else res--; now=fat[now]; } h[cnt++]=p; reverse(h,h+cnt); res++; now=g[0]; while(now!=p) { h[cnt++]=now; res++; now=fat[now]; } for(int i=0;i<cnt;i++) pos[b[h[i]]]=i; set<ll>dt; for(int i=1;i<cnt;i++) { ll d=0; if(pos[tmp[h[i]]]<i) d=i-pos[tmp[h[i]]]; else d=i+cnt-1-pos[tmp[h[i]]]; dt.insert(d); } if(dt.size()>1) { puts("-1"); exit(0); } ll d=*dt.begin(); return res+(d-1)*cnt; } } signed main() { read(n); for(int i=1;i<=n;i++) { read(a[i]); if(!a[i]) s=i; tmp[i]=a[i]; } for(int i=1;i<=n;i++) { read(b[i]); if(!b[i]) t=i; } for(int i=1;i<n;i++) { read(x); read(y); v[x].push_back(y); v[y].push_back(x); } dfs(t,0); ll now=s; while(fat[now]) swap(tmp[fat[now]],tmp[now]),f[now]=true,now=fat[now]; bool flag=true; for(int i=1;i<=n;i++) flag&=tmp[i]==b[i]; if(flag) { printf("0 %lld\n",dep[s]); exit(0); } for(int i=1;i<=n;i++) { if(tmp[i]!=b[i]) lis[++tot]=i; } sort(lis+1,lis+tot+1,cmp); set<ll>st; st.clear(); ll num=0; for(int i=1;i<=tot;i++) { if(vis[lis[i]]) continue; g.push_back(lis[i]); num++; ll now=lis[i]; vector<ll>c; c.clear(); while(now&&!vis[now]&&tmp[now]!=b[now]) c.push_back(now),vis[now]=true,now=fat[now]; for(auto x:c) tp[x]=now; st.insert(now); } if(num>2||st.size()>1) { puts("-1"); exit(0); } p=*st.begin(); if(num==1) x=p,y=lis[1]; else x=g[0],y=g[1]; ll ans=dep[s]; now=p; while(fat[now]) { if(!f[now]) ans++; else ans--; now=fat[now]; } ans+=dep[p]; ans+=min(calc1(),calc2()); printf("%lld %lld %lld\n",min(x,y),max(x,y),ans); exit(0); }
posted @   CelticOIer  阅读(28)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示