专栏文章
题解:P14480 化作彗星
P14480题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @minaxqgg
- 此快照首次捕获于
- 2025/12/01 23:26 3 个月前
- 此快照最后确认于
- 2025/12/01 23:26 3 个月前
曾经的我会做的题。
先判掉孤立点,接下来默认没有孤立点。
然后判掉 ,因为你什么操作都做不了。而且若 ,那么你无论怎么做操作都做不到第一个条件,所以接下来默认 且 。
先只考虑一个序列。设 满足 。对于每个 存在一个与其连边的 ,那么对于序列中一个子串都有 。意味着 这条边可以乱跑。
更加具体地说,若存在 满足 ,那么 。所以我们可以让任意一个点 变成走两步走到的 。
我们可以用并查集维护走 偶数 布能走到的点和走 奇数 步能走到的点。两个相邻的点若可以通过走 奇数 步走到一起,那么这两个点可以通过上面的操作凑成一条边。又因为一条边可以乱飞,我们就认为这两个点被删了。
我们用栈来维护这个过程,加入一个点的时候就和栈顶判断能否构成一对边,能就删栈顶,不能就加入当前点。最后合法的充分必要条件就是两个栈等价(即栈大小相同且对应点可以走 偶数 步互相到达)。
由于操作可逆,证明其充分性和必要性都是简单的,在这里我就不赘述了。
可能需要根据代码理解:
CPP#include <bits/stdc++.h>
using namespace std;
const int N=4e5+10;
int n,m,q,d[N];
unordered_map<int,int> G[N];
struct FaC{
int fa[N];
void init(){for(int i=1;i<=n*2;i++) fa[i]=i;}
int find(int x){return (fa[x]==x?x:fa[x]=find(fa[x]));}
void merge(int x,int y){
x=find(x),y=find(y);
if(x>y) swap(x,y);
fa[y]=x;
}
}F;
void read(){
cin>>m>>n>>q;
F.init();
int x,y;
for(int i=1;i<=m;i++){
cin>>x>>y;
F.merge(x,y+n),F.merge(x+n,y);
d[x]++,d[y]++;
G[x][y]=G[y][x]=1;
}
}
int len,a[N],b[N];
int topa,topb,sta[N],stb[N];
bool solve(int *a,int *b,int len){
if(len<=0) return 1;
int fl=0,fr;
for(int i=1;i<=len;i++) if(a[i]!=b[i]) fl=1;
if(fl==0) return 1;
fl=fr=0;
for(int i=1;i<len;i++){
if(G[a[i]][a[i+1]]) fl=1;
if(G[b[i]][b[i+1]]) fr=1;
}
if(fl==0 || fr==0) return 0;
topa=topb=0;
for(int i=1;i<=len;i++){
if(topa && F.find(sta[topa]+n)==F.find(a[i])) topa--;
else sta[++topa]=a[i];
if(topb && F.find(stb[topb]+n)==F.find(b[i])) topb--;
else stb[++topb]=b[i];
}
if(topa!=topb) return 0;
for(int i=1;i<=topa;i++){
if(F.find(sta[i])!=F.find(stb[i])) return 0;
}
return 1;
}
bool check(int *a,int *b,int len){
int lst=0;
for(int i=1;i<=len;i++){
if(!d[a[i]] && d[b[i]]) return 0;
if(d[a[i]] && !d[b[i]]) return 0;
}
for(int i=1;i<=len;i++) if(!d[a[i]]){
if(a[i]!=b[i]) return 0;
}
for(int i=1;i<=len+1;i++) if(i==len+1 || !d[a[i]]){
if(!solve(a+lst,b+lst,i-lst-1)) return 0;
lst=i;
}
return 1;
}
void work(){
while(q--){
cin>>len;
for(int i=1;i<=len;i++) cin>>a[i];
for(int i=1;i<=len;i++) cin>>b[i];
if(check(a,b,len)) cout<<"YES\n";
else cout<<"NO\n";
}
}
int main(){
ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
read();
work();
cerr<<1.0*clock()/CLOCKS_PER_SEC<<'\n';
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...