codeforces 并查集_CodeForces 763A(并查集/思维)

题意

一棵无根树中各个节点被染上了一种颜色c[i]

现在让你选择一个点作为根节点,使得这个根节点的所有儿子满足以该儿子节点的作为根的子树中所有点颜色均相同(不同儿子为根的子树颜色可以不同)

思路

俺的方法:

暴力水过。用并查集把相同颜色的连了边的点缩点,然后枚举每个点作为答案,判断这个点所连的的所有点的所在相同颜色连通块的大小之和是否等于n-1即可(除去自己这个点)。

正解:

先计算每个点与所连的点的颜色不同的点数,把两端颜色不同的边数也记录。如果某个点与连的点的不同颜色的个数==所有颜色不同的边数,那么这个点就是满足条件的。

这样想,作为根的这个点连的其他连通块肯定每个连通块颜色都是相同的,那么颜色不同的边只能在根这个点产生。

代码

俺的:

#include

using namespace std;

#define inf 0x3f3f3f3f

#define ll long long

const int N=100005;

const int mod=1e9+7;

const double eps=1e-8;

const double PI = acos(-1.0);

#define lowbit(x) (x&(-x))

int c[N],pre[N];

vector g[N];

int flag=0;

int find(int x)

{

if(x==pre[x])

return x;

return pre[x]=find(pre[x]);

}

set s[N];

int main()

{

std::ios::sync_with_stdio(false);

int n;

cin>>n;

for(int i=1; i

{

int u,v;

cin>>u>>v;

g[u].push_back(v);

g[v].push_back(u);

}

int q,mx=0;

for(int i=1; i<=n; i++)

{

cin>>c[i];

pre[i]=i;

}

for(int i=1; i<=n; i++)

{

int sz=g[i].size();

for(int j=0; j

{

if(c[i]==c[g[i][j]])

{

int fi=find(i),fj=find(g[i][j]);

if(fi!=fj)

pre[fj]=fi;

}

}

}

for(int i=1; i<=n; i++)

{

s[find(i)].insert(i);

}

int p,f=0;

for(int i=1; i<=n; i++)

{

int sum=0;

int sz=g[i].size();

for(int j=0; j

{

int v=g[i][j];

sum+=s[find(v)].size();

}

// cout<

if(s[i].size()!=1)

{

sum--;

}

if(sum==n-1)

{

p=i;

flag=1;

break;

}

}

if(!flag)

cout<

else

{

cout<

cout<

}

return 0;

}

/*

7

1 7

1 3

1 4

4 5

1 2

2 6

3 2 1 2 2 2 2

*/

/*

8

1 4

2 4

3 4

4 8

1 7

2 5

2 6

2 1 8 2 1 1 2 6

*/

正解:

#include

using namespace std;

#define inf 0x3f3f3f3f

#define ll long long

const int N=100005;

const int mod=1e9+7;

const double eps=1e-8;

const double PI = acos(-1.0);

#define lowbit(x) (x&(-x))

int c[N],s[N],u[N],v[N];

int main()

{

std::ios::sync_with_stdio(false);

int n;

cin>>n;

for(int i=1; i

{

cin>>u[i]>>v[i];

}

int q,mx=0;

for(int i=1; i<=n; i++)

{

cin>>c[i];

}

int sum=0;

for(int i=1;i

{

if(c[u[i]]!=c[v[i]])

s[u[i]]++,s[v[i]]++,sum++;

}

for(int i=1;i<=n;i++)

{

if(s[i]==sum)

{

cout<

return 0;

}

}

cout<

return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值