• CF1156D 0-1-Tree


    路径考虑顺序。

    显然合法的路径只有以下两种:

    1. 一段 (0) 加一段 (1) 或一段 (1) 加一段 (0)
    2. (0) 或全 (1)

    用并查集将边权为 (0)(1) 的边分别缩起来,对于一个大小为 (siz) 的联通块,第二种的答案是 (siz(siz-1))

    对于第一种,我们枚举 (0)(1) 的分界点,它所在 (0)(1) 的联通块大小分别是 (siz_0)(siz_1),它的答案是 ((siz_0-1)(siz_1-1))

    然后这题就做完了,时间复杂度 (O(nalpha(n)))

    code:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define N 2
    #define NN 200005
    #define For(i,x,y)for(i=x;i<=(y);i++)
    int fa[NN][N],siz[NN][N];
    int read()
    {
    	int A;
    	bool K;
    	char C;
    	C=A=K=0;
    	while(C<'0'||C>'9')K|=C=='-',C=getchar();
    	while(C>'/'&&C<':')A=(A<<3)+(A<<1)+(C^48),C=getchar();
    	return(K?-A:A);
    }
    int find(int p,bool type)
    {
    	if(fa[p][type]!=p)fa[p][type]=find(fa[p][type],type);
    	return fa[p][type];
    }
    inline void unite(int p,int q,bool type)
    {
    	p=find(p,type),q=find(q,type);
    	if(p==q)return;
    	if(siz[p][type]<siz[q][type])fa[p][type]=q,siz[q][type]+=siz[p][type];
    	else fa[q][type]=p,siz[p][type]+=siz[q][type];
    }
    int main()
    {
    	bool c;
    	ll ans=0;
    	int n,i,x,y;
    	n=read();
    	For(i,1,n)fa[i][0]=fa[i][1]=i,siz[i][0]=siz[i][1]=1;
    	For(i,1,n-1)
    	{
    		x=read(),y=read(),c=read();
    		unite(x,y,c);
    	}
    	For(i,1,n)ans+=1LL*(siz[find(i,0)][0]-1)*(siz[find(i,1)][1]-1);
    	For(i,1,n)
    	{
    		ans+=1LL*siz[find(i,0)][0]*(siz[find(i,0)][0]-1)+1LL*siz[find(i,1)][1]*(siz[find(i,1)][1]-1);
    		siz[find(i,0)][0]=siz[find(i,1)][1]=0;
    	}
    	cout<<ans;
    	return 0;
    }
    
  • 相关阅读:
    JS相关
    简单的打字效果
    android文件保存
    android 各种布局技术
    Android中的显示单位
    第一个android项目目录结构说明
    安装运行第一个android应用
    android手机模拟器屏幕分辨率说明
    系统常用VC++运行时下载地址
    VC++共享文件夹
  • 原文地址:https://www.cnblogs.com/May-2nd/p/13832550.html
Copyright © 2020-2023  润新知