专栏文章
题解:P13583 [NWRRC 2023] Colorful Village
P13583题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @miodzwte
- 此快照首次捕获于
- 2025/12/02 17:39 3 个月前
- 此快照最后确认于
- 2025/12/02 17:39 3 个月前
题意
有一个节点数为 的树。每个节点有一个颜色,一共 种颜色,每种颜色各有 个对应节点。在树上找一个大小为 的连通块,要求其中恰好包含每种颜色的节点各 个。
思路
记 表示第 个节点是否被选入集合内, 代表选入。
任意位置的连通块并不好做,所以我们考虑枚举第 种颜色所选的节点 强制加入集合内。令 为根,则连通块可以看作到根节点的连通性。
此时所有的要求条件可以看作如下集中限制:
- 强制 加入集合,即强制 ;
- 连通性:设 为 在树上的父亲节点,则有 和 ;
- 每种颜色各 个节点:设 和 为颜色相同的两个节点,则有 。
上述限制都可以用 2-SAT 解决。
做两次 2-SAT 即可,时间复杂度 。
CPP#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,c[200005],w[100005][2],ans[100005],tot;
vector<int> edget[200005];
void addt(int u,int v){edget[u].push_back(v);}
vector<int> edge[400005];
void add(int u,int v){edge[u].push_back(v);}
void dfst(int u,int fa){
for(int i=0,in=edget[u].size();i<in;i++){
int v=edget[u][i];
if(v!=fa)add(2*n+u,2*n+v),add(v,u),dfst(v,u);
}
}
int lo[400005],xh[400005],dfn,h[400005],toth;
int z[400005],zd,us[400005];
void dfs(int u){
lo[u]=xh[u]=++dfn,z[++zd]=u,us[u]=1;
for(int i=0,in=edge[u].size();i<in;i++){
int v=edge[u][i];
if(!xh[v])dfs(v),lo[u]=min(lo[u],lo[v]);
else if(us[v])lo[u]=min(lo[u],xh[v]);
}
if(lo[u]==xh[u]){
++toth;
while(z[zd]!=u)h[z[zd]]=toth,us[z[zd]]=0,--zd;
h[z[zd]]=toth,us[z[zd]]=0,--zd;
}
}
bool sat(int x){
for(int i=1;i<=4*n;i++)edge[i].clear();
add(2*n+x,x);
dfst(x,0);
for(int i=1;i<=n;i++){
int u=w[i][0],v=w[i][1];
add(u,2*n+v),add(2*n+u,v);
add(v,2*n+u),add(2*n+v,u);
}
for(int i=1;i<=4*n;i++)lo[i]=xh[i]=0;
dfn=toth=0;
for(int i=1;i<=4*n;i++)if(!xh[i])dfs(i);
for(int i=1;i<=2*n;i++)if(h[i]==h[i+2*n])return false;
tot=0;
for(int i=1;i<=2*n;i++)if(h[i]<h[i+2*n])cout<<i<<' ';
cout<<'\n';
return true;
}
void work(){
cin>>n;
for(int i=1;i<=n;i++)w[i][0]=w[i][1]=0;
for(int i=1;i<=2*n;i++){
cin>>c[i];
if(w[c[i]][0]==0)w[c[i]][0]=i;else w[c[i]][1]=i;
}
for(int i=1;i<=2*n;i++)edget[i].clear();
for(int i=1;i<2*n;i++){
int u,v;cin>>u>>v;
addt(u,v),addt(v,u);
}
bool check;
check=sat(w[1][0]);
if(check)return;
check=sat(w[1][1]);
if(check)return;
cout<<-1<<'\n';
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
int T;cin>>T;
while(T--)work();
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...