ABC327D题解
题意
给定
Sol
因为值只有
具体解法大概是对于一个节点
对于「
这样我们得到了一张有向图,只需要在这张有向图上跑 Tarjan 求强连通分量,同一强连通分量的点取值是相同的(
最后只需要对于每个点判断
时间复杂度
Code
#include<bits/stdc++.h>
#include<bits/extc++.h>
#define ll long long
#define N 2000005
#define endl "\n"
#define fi first
#define se second
using namespace std;
const ll mod=1e9+7;
ll low[N],dfn[N],cnt,vis[N],bel[N];
stack <ll> q;
ll ans;
ll a[N],b[N];
vector<ll> v[N];
ll n,m;
void tarjan(ll x){
low[x]=dfn[x]=++cnt;
q.push(x);
vis[x]=1;
for(auto y:v[x]){
if(!dfn[y]){
tarjan(y);
low[x]=min(low[x],low[y]);
}else if(vis[y]) low[x]=min(low[x],dfn[y]);
}
if(low[x]==dfn[x]){
ans++;
while(1){
auto t=q.top();
bel[t]=ans;
vis[t]=0;
q.pop();
if(t==x)break;
}
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++)cin>>a[i];
for(int i=1;i<=m;i++){
cin>>b[i];
v[a[i]].push_back(b[i]+n);// a为1则b为0
v[a[i]+n].push_back(b[i]);// a为0且b为1
}
for(int i=1;i<=n*2;i++)if(!dfn[i])tarjan(i);
for(int i=1;i<=n;i++){
if(bel[i]==bel[i+n]){//判断i所属强连通分量和i+n所属强连通分量相同
cout<<"No\n";
return 0;
}
}
cout<<"Yes\n";
return 0;
}
拓展
Q:如果让我们输出合法的方案,应该怎样做呢?
A:考虑每个点 那就在同一个强连通分量里面同时 取。
进行 Tarjan 得到的强连通分量编号便是反着的拓扑序(越靠近开始节点的编号越大),所以若
for(int i=1;i<=n;i++){
if(bel[i]==bel[i+n]){
cout<<"No\n";
return 0;
}
if(bel[i]<bel[i+n])res[i]=1;
}
cout<<"Yes\n";
for(int i=1;i<=n;i++)cout<<res[i]<<" ";